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 ...
随机推荐
- ORACLE查看数据文件包含哪些对象
在上篇ORACLE查看表空间对象中,我介绍了如何查询一个表空间有那些数据库对象,那么我们是否可以查看某个数据文件包含那些数据库对象呢?如下所示 SELECT E.SEGMENT_TYPE ...
- asp.net mvc jQuery 城市二级联动
页面效果图: 数据库表结构: 首先在数据库中创建省级.城市的表,我的表如下:我用了一张表放下了省级.城市的数据,用level划分省份和城市,parentId表示该城市所在省份的id 主要文件有:ind ...
- 伪造http的ip地址,突破ip限制的投票程序
某WEB投票程序, 使用 ip 限制和cookie限制技术,来限制每个ip每天只能投一次票,使用的是php开发,获取访问者的 ip 使用了搜狐的接口: http://txt.go.sohu.com/i ...
- Storm系列(一):搭建dotNet开发Storm拓扑的环境
上篇博客比较了目前流行的计算框架特性,如果你是 Java 开发者,那么根据业务场景选择即可:但是如果你是 .Net 开发者,那么三者都不能拿来即用,至少在这篇文章出现之前是如此.基于上篇文章的比较发现 ...
- 使用SQL语句创建SQL数据脚本(应对万网主机部分不支持导出备份数据)
1.查询待导出表Ad中的数据. SELECT * FROM [DB_Temp].[dbo].[Ad] 2.编写存储过程. --将表数据生成SQL脚本的存储过程 CREATE PROCEDURE dbo ...
- MMORPG大型游戏设计与开发(客户端架构 part15 of vegine)
一个接口需要统一的派生接口,这样做的好处在于能够统一的进行管理.我所知的脚本语言中,接口有多重接口,也还有所谓的虚基类,这些都是方便类的管理.在vengine(微引擎)中,统一的的接口管理为kerne ...
- JavaSE之概述与基本语法
嘛,这个本来应该发在OOP之前的,无所谓了,补发一下,这篇文章只会对JavaSE的语法做一个基本的概述而已,我会在最近新开一个新坑,也就是JavaEE系列,以后还会有Cpp(相对于C++,我还是更喜欢 ...
- POJ1426Find The Multiple[BFS]
Find The Multiple Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 27433 Accepted: 114 ...
- 重写成员“log4net.Util.ReadOnlyPropertiesDictionary.GetObjectData(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)”时违反了继承安全性规则
在.NET 4.0下使用最新版本的log4Net 1.2.10,会遇到下面这样的错误: 重写成员“log4net.Util.ReadOnlyPropertiesDictionary.GetObject ...
- 向Tiny6410移植QT4.7.0版本
在移植QT之前我们首先要安装tslib,没有移植的可以看这篇文章移植. http://www.cnblogs.com/ynxf/p/5392476.html step 1: echo yes |../ ...