HTML5 postMessage 跨域交换数据
前言
之前简单讲解了利用script标签(jsonp)以及iframe标签(window.name、location.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判断是否来自于正确可靠的发送方。
参考
- Window.postMessage()
- HTML5的postMessage使用记要
- Cross-window messaging with postMessage
- HTML5 postMessage 和 onmessage API 详细应用
HTML5 postMessage 跨域交换数据的更多相关文章
- 关于试用jquery的jsonp实现ajax跨域请求数据的问题
我们在开发过程中遇到要获取另一个系统数据时,就造成跨域问题,这就是下文要说的解决办法: 先我们熟悉下json和jsonp的区别: 使用AJAX就会不可避免的面临两个问题,第一个是AJAX以何种格式来交 ...
- JavaScript跨域提交数据
1.通过jsonp跨域 场景:假设前台有JS方法"crossJS", 1.1发送请求http://www.xxx.com/?callback=crossJS.(创建一个scr ...
- jquery ajax跨域取数据
jsonp.js/html 主要是利用jquery ajax和jsonp的datatype 跨站点请求数据,记录~ 同源策略:同端口,同协议,同域:所以ajax不能支持跨域取得数据,解决方案一般是js ...
- js跨域请求数据的3种常用的方法
由于js同源策略的影响,当在某一域名下请求其他域名,或者同一域名,不同端口下的url时,就会变成不被允许的跨域请求.那这个时候通常怎么解决呢,对此菜鸟光头我稍作了整理:1.JavaScript 在 ...
- postMessage 跨域
基于 postMessage 和 localStorage 的跨域本地存储方案 安·记 2014-09-07 2099 阅读 跨域 存储 localStorage HTML5 的 postMessag ...
- 利用location.hash+iframe跨域获取数据详解
前言 如果看懂了前文利用window.name+iframe跨域获取数据,那么此文也就很好理解了.一样都是动态插入一个iframe,然后把iframe的src指向服务端地址,而服务端同样都是输出一段j ...
- HTML5解决跨域问题
HTML5解决跨域问题 由于浏览器的同源策略,网络连接的跨域访问是不被允许的,XHR对象不能直接与非同源的网站处理数据交互.而同源指的是什么呢?同源的范畴包括:规则(协议),主机号(域名.ip等),端 ...
- jQuery之ajax的跨域获取数据
如果获取的数据文件存放在远程服务器上(域名不同,也就是跨域获取数据),则需要使用jsonp类型.使用这种类型的话,会创建一个查询字符串参数 callback=? ,这个参数会加在请求的URL后面.服务 ...
- 利用window.name+iframe跨域获取数据详解
详解 前文提到用jsonp的方式来跨域获取数据,本文为大家介绍下如何利用window.name+iframe跨域获取数据. 首先我们要简单了解下window.name和iframe的相关知识.ifra ...
随机推荐
- zookeeper集群某个follower启动失败
配置完成zookeeper集群,发现有一个节点,进程正常但是状态异常 查看日志一开始进入歧途了,查看的是这个目录 其实应该查看这个目录的日志 失败日志: 很明显,没有权限,更改权限,启动成功
- Java api 入门教程 之 JAVA的IO处理
IO是输入和输出的简称,在实际的使用时,输入和输出是有方向的.就像现实中两个人之间借钱一样,例如A借钱给B,相对于A来说是借出,而相对于B来说则是借入.所以在程序中提到输入和输出时,也需要区分清楚是相 ...
- Tomcat源码分析之—组件启动实现分析
Tomcat由多个组件组成,那么Tomcat是怎么对他们的生命周期进行管理的么,这里将从Tomcat源码去分析其生命周期的实现: Bootstrape类为Tomcat的入口,所有的组件够通过实现Lif ...
- history
history用来显示最近执行的命令,系统中将当前的允许的最大保存的历史命令条数保存在环境变量HISTSIZE中,缺省选项时表示显示最多HISTSIZE个命令,可以指定显示最近的n条命令 $histo ...
- php模拟飞鸽传输协议,代码实现向飞鸽发送消息
飞鸽传书协议:1:23149:riverlet:127.0.0.1:\x20:balabalabalabala版本号:包编号:发送者姓名:发送者主机名:命令字:附加信息(消息内容) <?php ...
- 通过SecureCRT访问亚马逊Amazon EC2主机
亚马逊推出了免费的云主机服务器 Amazon EC2,它是通过安全密钥来访问主机的. 问题是下载的密钥在SecureCRT 上无法直接使用,需要转换. 下面的方法可以在自己的linux主机上生成sec ...
- IOS中修改图片的大小:修改分辨率和裁剪
在IOS开发中,经常有限制图片文件大小的,有的用户图片很大,导致上传时间慢,造成问题. 如:微信分享中,如果图片的大小好像大于50kbytes,就分享失败,而且没有任何提示. 所以,我添加了两个函数: ...
- 解决AutoCAD2010在VS2010上无法命中断点
AutoCAD 2010的二次开发告一段落,现在整理一些开发中遇到的问题. 最早遇到的问题是关于AutoCAD 2010在VS 2010上无法调试.奇怪的是这问题只出现在我同事电脑上,我的电脑一切OK ...
- chrome内核浏览器input边框
直接给input加outline:none和设置input {outline:none}都没效 最后逼得没法,*:focus { outline: none; },然后整个世界就安静了,嚯嚯
- WEB安全--逻辑漏洞
业务逻辑问题是一种设计缺陷.逻辑缺陷表现为设计者或开发者在思考过程中做出的特殊假设存在明显或隐含的错误.精明的攻击者会特别注意目标应用程序采用的逻辑方式,设法了解设计者与开发者做出的可能假设,然后考虑 ...