HTML5 postMessage 跨域交换数据

前言

  之前简单讲解了利用script标签(jsonp)以及iframe标签(window.namelocation.hash)来跨域交换数据,今天我们来学习一下HTML5的api,利用postMessage来跨域交换数据。和前面一些方式交换数据方式不同的是,利用postMessage不能和服务端交换数据只能在两个窗口(iframe)之间交换数据,废话不多说,我们直接进入实战。

实战postMessage

  • overview

  上文中说,postMessage是用于两个窗口(iframe)之间交换数据的,如果我们同时打开着百度和谷歌两个页面,是不是说这两者之间就可以通信了?No,no,no,事实并非如此,就算百度和谷歌俩页面有通信的意愿也不行。两个窗口能通信的前提是,一个窗口以iframe的形式存在于另一个窗口,或者一个窗口是从另一个窗口通过window.open()或者超链接的形式打开的(同样可以用window.opener获取源窗口);换句话说,你要交换数据,必须能获取目标窗口(target window)的引用,不然两个窗口之间毫无联系,想通信也无能为力。

  既然是H5家族的,我们也得观望下它被广大浏览器的接受程度(具体细节check can I use postMessage),可以看到接受程度还是相当高的:

  而postMessage的使用方式也相当简单:

otherWindow.postMessage(message, targetOrigin, [transfer]);

  otherWindow是对接收方窗口的引用,一般可以是以下几种方式:

window.frames[0].postMessage
document.getElementsByTagName(‘iframe‘)[0].contentWindow
window.opener.postMessage
event.source.postMessage
window.open 返回的引用
...

  而message顾名思义就是发送的数据内容,支持字符串、数字、json等几乎所有形式的数据(详见The structured clone algorithm

  targetOrigin是接收方的URI(协议+主机+端口),也可以是url形式,但之后的内容(形如xx.html)会自动忽略;用通配符*可以指定所有域,但是切记不要用(for security)。

  transfer可省略,没看懂是啥意思...以后有需要的时候再研究

  而接受方窗口一般监听message事件,详见下面的例子。

  • window <-> iframe

  假设index页面有个iframe(不同源),我们要给iframe发送数据,而iframe得到数据后也发送数据给top window,表示“我"得到数据了。直接看源码(思考如何发送and如何接收):

<!-- http://localhost:81/fish/index.html -->
<script type="text/javascript">
  // 页面加载完后才能获取dom节点(iframe)
  window.onload = function(){
    // 向目标源发送数据
    document.getElementsByTagName(‘iframe‘)[0].contentWindow.postMessage({"age":10}, ‘http://localhost:8080‘);
  };

  // 监听有没有数据发送过来
  window.addEventListener(‘message‘, function(e) {
      console.log(e);
  });
</script>
<iframe src="http://localhost:8080/index.html"></iframe>
<!-- http://localhost:8080/index.html -->
<script type="text/javascript">
  // 监听有没有数据发送过来
  window.addEventListener(‘message‘, function(e){
      // 判断数据发送方是否是可靠的地址
      if(e.origin !== ‘http://localhost:81‘)
        return;
    // 打印数据格式
    console.log(e);
    // 回发数据
    e.source.postMessage(‘hello world‘, e.origin);
  }, false);
</script>

  我们截图看看打印的东西究竟长什么样(index页面传给iframe的数据):

  红框标出的是三个最重要的属性,data顾名思义就是传输的数据了;origin就是发送消息窗口的源(URI 协议+主机+端口);而source就能引用发送消息的窗口对象(可以用它来引用发送窗口进行消息回传)。

   在消息接收端监听可以监听message事件(代码如上),当然如果要兼容坑爹的ie肯定要用attachEvent。这里不推荐使用window.onmessage,兼容性不大好(比如不能兼容低版本ff)。

  • window <-> window

  说完了跟同一页面中的iframe的数据交换,再来说说两个窗口之间的数据交换。我们知道用window.open()可以打开一个新的窗口,而如果两个窗口同源,则两个窗口的通信将会非常简单,我们可以通过window.opener.functionName在新窗口中调用原来窗口的方法(和变量)。但是如果两个窗口不同源,这样的操作将会变得很艰难,幸运的是H5给我们提供了postMessage,使得window.opener.postMessage()不会报错!demo很简单:

<!-- http://localhost:81/fish/index.html -->
<script type="text/javascript">
  // 打开一个新的窗口
  var popup = window.open(‘http://localhost:8080/index.html‘);

  /// When the popup has fully loaded, if not blocked by a popup blocker:
  setTimeout(function() {
      // 当前窗口向目标源传数据
    popup.postMessage({"age":10}, ‘http://localhost:8080‘);
  }, 1000);
</script>
<!-- http://localhost:8080/index.html -->
<script type="text/javascript">
  // 设置监听,如果有数据传过来,则打印
  window.addEventListener(‘message‘, function(e) {
    console.log(e);
    // console.log(e.source === window.opener);  // true
  });
</script>

  这里要设置一个定时器的原因是向目标窗口发送数据必须等目标窗口完全加载完,也就是说要在目标窗口中先设置好“监听器”,发送窗口发的数据才能被监听到,所以给了个定时器delay,而因为加载时间的不确定所以定时器的delay值也不能确定;另外一个可行的办法是当目标页面加载完后,发个消息个源页面(postMessage),而源页面收到消息,再用postMessage发送消息给目标页面。

安全顾虑

  提到跨域交换数据,条件反射都会问一句,安全吗?对于postMessage,答案是肯定的。

  postMessage采用的是“双向安全机制”。发送方发送数据的时候,会确认接受方的源(所以最好不要用*),而接受方监听到message事件后,也可以用event.origin判断是否来自于正确可靠的发送方。

参考

  1. Window.postMessage()
  2. HTML5的postMessage使用记要
  3. Cross-window messaging with postMessage
  4. HTML5 postMessage 和 onmessage API 详细应用
时间: 2024-08-15 19:39:03

HTML5 postMessage 跨域交换数据的相关文章

【h5】h5数据跨域交换postMessage用法

h5数据跨域交换postMessage用法 来源 1.与通过window.open()打开的新窗口跨域数据交换,代码如下: (1)源窗口 1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"> 5 <title>源窗口</title> 6 </head> 7 <body> 8 <b

JavaScript跨域提交数据

1.通过jsonp跨域    场景:假设前台有JS方法"crossJS", 1.1发送请求http://www.xxx.com/?callback=crossJS.(创建一个script标签,请求该地址) 1.2后台服务器,返回数据格如crossJS({"a":"b"}); 优点:开发.维护简单 缺点:每次可提交数据大小受get方式限制 2.使用HTML5中新引进的window.postMessage方法来跨域传送数据   场景: 页面http:

js跨域请求数据的3种常用的方法

由于js同源策略的影响,当在某一域名下请求其他域名,或者同一域名,不同端口下的url时,就会变成不被允许的跨域请求.那这个时候通常怎么解决呢,对此菜鸟光头我稍作了整理:1.JavaScript   在原生js(没有jQuery和ajax支持)的情况下,通常客户端代码是这样的(我假设是在localhost:8080的端口下的http://localhost:8080/webs/i.mediapower.mobi/wutao/index.html页面的body标签下面加入以下代码): <script

谈谈跨域请求数据的几种常用的方法

由于js同源策略的影响,当在某一域名下请求其他域名,或者同一域名,不同端口下的url时,就会变成不被允许的跨域请求. 那这个时候通常怎么解决呢,对此菜鸟光头我稍作了整理: 1.JavaScript 在原生js(没有jQuery和ajax支持)的情况下,通常客户端代码是这样的(我假设是在localhost:8080的端口下的http://localhost:8080/webs/i.mediapower.mobi/wutao/index.html页面的body标签下面加入以下代码): <script

笔记-Ajax[4]-JSONP跨域获取数据。

JS的跨域:跨域名获取数据,a域名获取b域名中的数据. 解决跨域获取数据的方法也叫JSONP(JSON and Padding) JSONP方法: 1:服务器代理:XMLHttpRequest代理文件 2:script标签:jsonp(常用);//利用script标签的src引入外部文件的功能,src能够引入任何的文件的类型 3:location.hash方式:iframe 4:window.name方式 5:flash方式 6:html5的postMessage方式 例子:百度输入数据下拉框提

HTML5解决跨域问题

HTML5解决跨域问题 由于浏览器的同源策略,网络连接的跨域访问是不被允许的,XHR对象不能直接与非同源的网站处理数据交互.而同源指的是什么呢?同源的范畴包括:规则(协议),主机号(域名.ip等),端口号. 但是随着开放,共享平台的流行,跨域访问的需求愈加强烈.目前最常用的跨域方案是动态加入script标签,这多少有点hack的意味,跨域访问似乎一直没有什么安全且光明正大的办法. 终于,HTML5提供的XMLHttpRequest Level2实现了跨域访问以及其他的一些新功能.下面我们会详细讨

跨域请求数据解决方案整理

转自:http://www.cnblogs.com/xyang/archive/2012/05/18/2507845.html 跨域请求数据解决方案主要有如下解决方法: JSONP方式 表单POST方式 服务器代理 Html5的XDomainRequest Flash request 分开说明: 一.JSONP: 直观的理解: 就是在客户端动态注册一个函数 function a(data),然后将函数名传到服务器,服务器返回一个a({/*json*/})到客户端运行,这样就调用客户端的 func

XMLHTTPRequest对象不能跨域获取数据?!

写了一小段代码,是用XMLHTTPRequest对象来获取数据的,在本地服务器中,运行的很顺利,但是转向实际服务器(实质上就是转向http://gumball.wickedlysmart.com获取一个json文件过来),运行就跑不起来了. 这就涉及到跨域获取数据的问题了. 我运行时的环境是这样的: 本地服务器运行当前代码.转向http://gumball.wickedlysmart.com获取一个json文件过来. 结果:报错. XMLHttpRequest cannot load   No

利用window.name+iframe跨域获取数据详解

详解 前文提到用jsonp的方式来跨域获取数据,本文为大家介绍下如何利用window.name+iframe跨域获取数据. 首先我们要简单了解下window.name和iframe的相关知识.iframe是html的一个标签,可以在网页中创建内联框架,有个src属性(指向文件地址,html.php等)可以选择内联框架的内容,可以看个例子(猛戳这里),大概了解下就行了.window.name(一般在js代码里出现)的值不是一个普通的全局变量,而是当前窗口的名字,这里要注意的是每个iframe都有包