1、介绍
window.postMessage() 方法允许来自一个文档的脚本可以传递文本消息到另一个文档里的脚本,不用管是否跨域。一个文档里的脚本还是不能调用在其他文档里方法和读取属性,但他们可以用window.postMessage结合window.addEventListene这种消息传递技术来实现安全的通信。这项技术称为“跨文档消息传递”,又称为“窗口间消息传递”或者“跨域消息传递”。
(1)window.addEventListene
用法:
window.addEveantListener('message',(event)=>{})
event的属性:
data: 从其他 window 传递过来的数据副本。
origin: 调用 postMessage 时,消息发送窗口的 origin。例如:“http://www.localhost:8080”。
source: 对发送消息的窗口对象的引用。可以使用此来在具有不同 origin 的两个窗口之间建立双向数据通信
(2)postMessage() 方法
该方法允许有限的通信 —— 通过异步消息传递的方式 —— 在来自不同源的脚本之间。
postMessage 可用于解决以下方面的问题:
页面和其打开的新窗口的数据传递
页面与嵌套的 iframe 消息传递
多窗口之间消息传递
用法:
otherWindow.postMessage(message, targetOrigin, [transfer]);
属性:
otherWindow:其他窗口的一个引用,比如 iframe 的 contentWindow 属性、执行 window.open 返回的窗口对象、或者是命名过或数值索引的 window.frames。
message:要发送的数据。它将会被结构化克隆算法序列化,所以无需自己序列化(部分低版本浏览器只支持字符串,所以发送的数据最好用JSON.stringify() 序列化)。
targetOrigin:通过 targetOrigin 属性来指定哪些窗口能接收到消息事件,其值可以是字符串“*”(表示无限制)或者一个 URI(如果要指定和当前窗口同源的话可设置为"/")。在发送消息的时候,如果目标窗口的协议、主机地址或端口号这三者的任意一项不匹配 targetOrigin 提供的值,那么消息就不会发送
2、场景
(1)不同 origin 的两个窗口之间建立双向数据通信( 不同端口下的窗口,不同网站地址)
// localhost:9999/index页面
// 接收消息
window.addEventListener('message', (e) => {
console.log(e.data)
})
// 发送消息
const targetWindow = window.open('http://localhost:8888/user');
setTimeout(()=>{
targetWindow.postMessage('来自9999的消息', 'http://localhost:8888')
}, 3000)
/**
// localhost:8888/user页面
//接收数据
window.addEventListener('message', (e) => {
console.log(e.data)
if (event.origin !== "http://localhost:9999")
return;
// 发送数据
e.source.postMessage('来自8888的消息', e.origin)
})
(2)页面与嵌套的 iframe 消息传递
// 在引用iframe的index.html页面中
<iframe id="iframe" src="./demoIframe"></iframe>
<script>
var iframe = document.getElementById('iframe');
iframe.onload = function() {
// 向demoIframe发送跨域数据
iframe.contentWindow.postMessage('来自index.html的消息', 'index.html');
};
// 接收demoIframe返回数据
window.addEventListener('message', (e) => {
console.log(e.data);
}, false);
</script>
// 在iframe的demoIframe.html页面中
<script>
// 接收index.html的数据
window.addEventListener('message',(e) => {
console.log(e.data);
if(e.origin !== 'index.html')
return;
// 发送消息给index.html
window.parent.postMessage('来自demoIframe.html的消息', e.origin);
//当iframe嵌入页面时。window.parent为iframe嵌入的父级
}, false);
</script>
3、安全问题
如果你不希望从其他网站接收 message,请不要为 message 事件添加任何事件监听器。
如果你确实希望从其他网站接收message,请始终使用 origin 和 source 属性验证发件人的身份。
当你使用 postMessage 将数据发送到其他窗口时,始终指定精确的目标 origin,而不是 *