使用postMessage进行跨域通信

跨域通信是前端开发中经常会遇到的情景,跨域通信有多种多样的方式,今天就详细说一下使用 postMessage 这样方式进行跨页面脚本的数据通信。

一、认识 window.postMessage

根据 MDN 的官方文档解释:window.postMessage() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为 https),端口号(443 为 https 的默认值),以及主机 (两个页面的模数 Document.domain 设置为相同的值) 时,这两个脚本才能相互通信。

二、使用语法

1、向目标窗口发送消息

  otherWindow.postMessage(message,targetOrigin)
  • otherWindow

    其他窗口的一个引用,比如 iframe 的 contentWindow 属性、执行 window.open 返回的窗口对象、或者是命名过或数值索引的 window.frames。

  • message

    将要发送到其他窗口的数据。

  • targetOrigin

    指定哪些窗口能接收到消息,其值可以是字符串"*"(表示无限制)或者一个 URI,在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配 targetOrigin 提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口.

2、目标窗口接收消息

  window.addEventListener("message", receiveMessage, false);
  function receiveMessage(event){
    // event.origin 表示消息的来源地址
    // event.data 表示接收到的数据
    if (event.origin !== 'http: //www.xxxx.com') {
      return
    } else {
      console.log(event.data)
    }
  }

三、具体案例

父窗口主动给子窗口发消息

本案例是在 Vue2.0+iView3.0 的环境下进行,在一个弹框内嵌套一个 iframe 页面。

  • 模板

    <button @click="show">显示</button>
    <Modal
      v-model="isModalShow"
      width="80%"
      class-name="select_rules_modal"
      footer-hide
      @on-visible-change="visibleModalChange"
    >
      <div class="rules_header">iFrame页面</div>
      <div class="rules_body">
        <iframe
          class="rules_iframe"
          src="http://www.target.com:9900/list"
          id="iframe"
          ref="iframe"
          v-if="isModalShow"
        ></iframe>
      </div>
    </Modal>
    
  • 逻辑

    data() {
      return {
        isModalShow: false
      }
    },
    methods: {
      show(){
        this.isModalShow = true
        let iframe = document.getElementById('iframe')
        let data = 'hello'
        if (iframe.attachEvent){ // 兼容IE写法
            // 必须在ifame页面加载完毕后才能发送消息,否则对方接收不到
            iframe.attachEvent("onload", function(){
              // 发消息
              iframe.contentWindow.postMessage(data, 'http://target.com:9900')
            })
          } else {
            iframe.onload = function(){
              // 发消息
              iframe.contentWindow.postMessage(data, 'http://target.com:9900')
          }
        }
        // 收消息(在目标页面进行相关操作,接收发送过来需要的数据)
        window.addEventListener('message',this.receiveMessage,false)
      },
      // 接收消息回调
      receiveMessage(event){
        // 判断是否是目标地址发过来的消息,否则不接收
         if (event.origin !== 'http://target.com:9900') {
          return
        } else {
          // event.data 为接收到的数据
          console.log(event.data)
          // 处理数据.....
          this.isModalShow = false
        }
      },
      // 弹框关闭时移除消息监听
      visibleModalChange(){
        window.removeEventListener('message',this.receiveMessage,false)
      }
    }
    

    子窗口主动给父窗口发送消息

    思路: 子窗口无法直接给父窗口发消息,因为存在跨域问题,如果要实现子窗口给父窗口发送消息,需要父窗口先给子窗口发送一个消息,子窗口记住事件源,然后才可以实现发送消息给父窗口。
    1、父窗口在 iframe 加载完后发送消息,并监听子窗口的消息

    let iframe = document.getElementById("iframe");
    if (iframe.attachEvent) {
      // 兼容IE写法
      iframe.attachEvent("onload", function () {
        // 发消息
        iframe.contentWindow.postMessage(data, "https://yyy.com");
      });
    } else {
      iframe.onload = function () {
        // 发消息
        iframe.contentWindow.postMessage(data, "https://yyy.com");
      };
    }
    // 收消息
    window.addEventListener("message", this.receiveChildMessage, false);
    .......
    receiveChildMessage(event) {
      //.......
    }
    

    2、子窗口在页面加载完毕后监听消息,收到消息后保存事件源

    window.addEventListener("message", this.receiveParentMsg, false);
    .....
    receiveParentMsg(event) {
        if (event.origin !== 'http://xxx.com'){
            return
        }
        // 存储事件源,以便于保存时发消息
        this.parentEvent = event
    },
    

    3、事件触发时给父窗口发送消息

    this.parentEvent.source.postMessage("发送消息", this.parentEvent.origin);
    

    4、页面销毁时移除消息监听

    window.removeEventListener("message", this.receiveParentMsg, false);
    

    四、注意事项

    1、需要通过onload的事件监听iframe页面加载完毕后在发生消息,发送接收不到。

    2、一定要在页面关闭的时候移除监听事件,否则会导致在每打开一次iframe页面,接收的消息会叠加一次的问题。

    3、如果是父窗口 iframe 加载完后发消息,子窗口页面加载后监听消息,一定要注意子窗口监听消息要在父窗口发消息以前,否则可能收不到消息,放在哪个生命周期中根据自己情况处理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容

  • 1. 什么是跨域? 跨域一词从字面意思看,就是跨域名嘛,但实际上跨域的范围绝对不止那么狭隘。具体概念如下:只要协议...
    w_zhuan阅读 513评论 0 0
  • 概述 JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。但在安全限制的同时也给注入iframe...
    npmstart阅读 2,147评论 0 5
  • 原文来自:http://www.ruanyifeng.com/blog/2016/04/same-origin-p...
    神秘者007阅读 1,035评论 0 1
  • 什么是跨域 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实...
    HeroXin阅读 834评论 0 4
  • 一、概述 1.1 含义 1995年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。...
    会飞的贼er阅读 436评论 0 2