Window.postMessage() HTML5 跨域解决方案

Hey,everybody~

又是倒霉的跨域 T T , 有多少人死在了“说出你知道的跨域解决方案,越多越好?”这个面试问题上。

今天和大家说说,HTML5提供的一个跨域解决方案,Window.postMessage , 它足够易学好用,会让你眼前一亮。但是往往大多数情况下,都不会让人一直笑下去,俗话说道高一尺魔高一丈,这个方法同样也会被HTTP的一些协议所限制着,比如X-Frame-Options:SAMEORIGIN,不过好在大多数情况下,情况不至于这么糟糕。下面进入正题:

Window.postMessage 提供了一种安全的跨域通讯方案。

语法


语法分为两部分,发和收,其实都很简单。

发送

otherWindow.postMessage( message , origin [ , transfer] )

* otherWindow

跨域的window对象的引用,比如iframe、window.open创建的对象等。

* message

发给跨域对象的消息,可以是string,object,number等对象

* origin

指定消息发送的域名,可以使用通配符 *

接收

我们可以监听window 的 "message" 事件来获取到传递过来的值,例如:

window.addEventListener('message',receiveMessage,false);

function receiveMessage(event){
    // ...
}

接收到的event包含下面几个重要的属性:

* data

传递过来的信息。

* origin

发送消息的域名,包含了协议和端口(如 https://developer.mozilla.org:443),通常情况下 默认端口会被省略,例如 https://www.google.com 意味着省略了端口443 , http://www.google.com 省略了端口 80。

* source

发送数据的window的引用,例如b域名收到a域名的消息,此时的source指的是a域名的window,你可以通过它来实现双向通讯。

举例:


好了,终于可以举个例子了,(等等我的糖炒板栗呢?)

示例页面:

http://jsbin.com/wecoqi

示例代码:

http://jsbin.com/wecoqi/9/edit?html,js

http://jsbin.com/qetuwicebo/9/edit?html,js

代码解释

用户打开A页面,点击Open Window按钮,打开一个新的B页面(由于资源有限,Demo中用同域作为演示), 回到A页面点击 push message 按钮 ,发送你好到B页面,同时收到B页面的反馈。 这时候回到B页面,就能看到B页面的收到的消息了。

具体代码如下。

A页面

//获取按钮以及显示文本的DOM
var openWindow = document.getElementById('open');
var pushMessage = document.getElementById('push');
var messageBox = document.getElementById('message');

var newWin;

//Open Window 按钮事件
openWindow.addEventListener('click',function(){
    //点击之后,打开一个新的窗口,并获得该窗口的引用
      newWin = window.open('http://jsbin.com/qetuwicebo');
})

pushMessage.addEventListener('click',function(){
    //点击发送消息按钮,发送你好到新打开的窗口
    //注意第二参数是接收消息的域名,虽然可以用*匹配所有的域名,
    //但是在生产环境中,强烈建议写成真实的域名,以防不必要的攻击
    newWin.postMessage('你好','*');
    //
    messageBox.innerHTML=  messageBox.innerHTML+'发送了消息“你好“,请移步新打开的页面查看收到的消息'
})

//监听message事件,已接收其他页面发来的信息
window.addEventListener('message',function(event){
  messageBox.innerHTML=  messageBox.innerHTML+'<br>收到了回复:'+event.data
})

B页面

//监听message事件
window.addEventListener("message", receiveMessage, false);

function receiveMessage(event ){
    //注意,在生产环境中,一定要验证event.origin,以避免潜在的安全问题
      var html='event.data: '+event.data+'<br>';
      html += 'event.origin: '+event.origin+'<br>';
      html += 'event.source: '+event.source+'<br>';
      document.getElementById('message').innerHTML= html;

      //收到消息之后我们会给,父页面发送一条回复
      //event.source可以获取到消息来源页面的引用
      event.source.postMessage('hi,我来之新打开的页面,我收到你post的消息了',event.origin);
}

结尾

不想写结尾,但是,如果不写 @Robin Ma 又要说我的文章结尾太唐突了。 好吧,这里是结尾,就这样。 对了,记得回复哦,这是最好的鼓励 ~ :)

Write a response...
Mofei Zhu
publish
Mofei
2017-01-14 11:21
@lucas  简单列一下我现在能想到的一些方法:
1. 最长用的jsonp
2. 通过Flash
3. 通过设置Access-Control-Allow-Origin:*
4. 子域跨域的js设置domain
5. 本文提到的postMessage()
6. 通过本域名的后台转发
其他的还有很多方法,这里没法一一列全,不过最重要的还是要根据具体情况来提出更合适的解决方案。
1
 Replay
@Mofei  
Replay
lucas
2016-10-12 18:50
支持支持. 不过文章开头提到了的面试问题, 并没有全面被回答. 只是给出了html5相关的解决方法. 如果能在那附近, 加上 相关文章的链接, 就更好啦. 

不过还是支持!
0
 Replay
@lucas  
Replay
Mofei
2015-04-08 19:26
@剧中人 业界牛人呀,引荐给你 哈哈
0
 Replay
@Mofei  
Replay
剧中人
2015-04-08 19:13
Robin Ma是谁?业界大牛么?求推荐求认识。
0
 Replay
@剧中人  
Replay