前言
出于安全和隐私的原因,Web浏览器会阻止不同域中的文档互相影响; 也就是说,跨站点脚本是不允许的。但很多时候需要跨域操作,因此开发出允许跨域方法document.domain,JSONP,CORS等。这些跨域方式都有一定的局限性,比如我最近遇到一个跨域问题,我在www.A.com域打开一个www.B.com域的网页,需要B网址操作完成后,前端通知A网址。上面这些方法都不能有效地跨越通信。
而这是我查看文档,发现HTML5提供了一种新的跨域方法 称为跨文档通信(cross-document messaging),这是作用于网页之间互相通信与发送信息的功能。使用这个功能,只要获取到网页所在窗口对象的实例,不仅同源(域 + 端口号)的 Web 网页之间可以互相通信,甚至可以实现跨域通信。 要想接收从其他窗口发送来的信息,必须对窗口对象的 message 事件进行监听,其它窗口可以通过 postMessage 方法来传递数据。
用法
1.前提A域名使用window.open打开B域名站点。
2.B域名发送一个信息“HI”给”http://www.A.com“。
var targetWindow = window.opener;
targetWindow.postMessage("HI", "http://www.A.com");
3.A域接收消息后,分析是”http://www.B.com“传来的 传回去”I’m fine”,给”http://www.A.com“。
window.addEventListener('message', receiver, false);
function receiver(e) {
if (e.origin == "http://www.B.com") {if (e.data == "HI") {e.source.postMessage("I'm fine", e.origin);} }
}
发送信息-postMessage
postMessage负责发送信息,向给定窗口发布消息。消息可以是结构化对象。
postMessage(data,origin)方法接受两个参数:
字段 | 介绍 |
---|---|
data | 要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果。 |
origin | 字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为”*”,这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为”/”。 |
例子
window.opener.postMessage(“HI”, “http://www.A.com“);
//这样 发送一个“HI”给 A 信息了。
接收事件-message
window新事件message,负责接送信息。通过发布一个message方法来,接听其网站的信息。postMessage(message,targetOrigin [,transfer ])
window.addEventListener(‘message’, function(e){console.log(e)}, false);
//这是一个接收器 接收信息输出。window.attachEvent(‘message’, function(e){console.log(e)}, false);
//IE9以下使用attachEvent
接收的对象用下面属性。
其中有几个重要属性
字段 | 介绍 |
---|---|
data | 接收message传递过来的值,值的类型是字符串形式。 |
source | 发送消息的窗口对象。 |
origin | 发送消息窗口的源(协议+主机+端口号)。 |
安全性
使用此API需要格外小心,因为这个是开方一个入口,允许大家来发送信息。
因此使用message应该设置好origin属性,以确保允许的域的信息。避免给其他恶意网址来利用攻击。
还有postMessage() 也要设置好origin,这样避免信息未经授权而被其他网站接收。不建议设置(*)
攻击者可以发送大量的消息; 如果接收页面执行昂贵的计算或导致为每个此类消息发送网络流量,则攻击者的消息可能会成倍增加,从而导致拒绝服务攻击。鼓励采用速率限制(每分钟只接受一定数量的消息)以使这种攻击不切实际。
兼容性
Chrome浏览器 64+
Chrome 4+
iOS Safari 3.2+
UC浏览器Android 11.8+
Firefox 3+
IE浏览器(限定) 8+
三星Internet 4+
Opera Mini 全部+
Safari 4+
Edge 12+
Android Browser 2.1 +
Opera 9.5+
来源:caniuse.com
注意事件
1.Cross-Document Messaging适合对窗口来互相传值使用,但如果要做页面跳转会被浏览器安全限制的。(IE浏览器限制不能别其他域来跳转)
2.使用需要清晰知道窗口关系,这样才能正确传递值。
iframe例子
父级页面A
function receiver(e) {
if (e.origin == "http://www.B.com") {if (e.data == "HI") {e.source.postMessage("I'm fine", e.origin);} }
}try{window.addEventListener('message', receiver, false);
}catch(e){window.attachEvent('message', receiver, false);
}
子级页面B
window.parent.postMessage("HI", "http://www.A.com");