使用postMessage进行Iframe跨域通信
最近遇到了一个问题:一个iframe页面需要和它的宿主页面进行通信,点击iframe的某个按钮iframe消失,主页面还可以向iframe传参。iframe页面和主页面是不同域名的页面, 这就涉及到跨域访问了,以前跨域资源访问都很麻烦,使用postMessage
可以很方便安全地进行跨域通信。
postMessage
window.postMessage() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。
window.postMessage() 方法被调用时,会在所有页面脚本执行完毕之后(e.g., 在该方法之后设置的事件、之前设置的timeout 事件,etc.)向目标窗口派发一个 MessageEvent 消息。 该MessageEvent消息有四个属性需要注意: message 属性表示该message 的类型; data 属性为 window.postMessage 的第一个参数;origin 属性表示调用window.postMessage() 方法时调用页面的当前状态; source 属性记录调用 window.postMessage() 方法的窗口信息。
语法
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow
其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
message
将要发送到其他 window的数据.从 Gecko 6.0 (Firefox 6.0 / Thunderbird 6.0 / SeaMonkey 2.3)开始,参数 message被使用结构化克隆算法进行序列化。这意味着您可以将各种各样的数据对象安全地传递到目标窗口,而不必自己序列化它们。在此之前只能传字符串。
targetOrigin
通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串”*“(表示无限制)或者一个URI.在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。
transfer 可选,太高级不常用
接下来根据我的需求来展示下postMessage
的用法,DOM结构如下:
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Document</title>
</head>
<body>
<iframe src="https://pc.xunlei.com/auth" id="authIframe"></iframe>
</body>
</html>
点击iframe上的按钮iframe消失
iframe向主页面发送数据
// iframe
window.parent.postMessage(JSON.stringify({
from: 'auth',
event: 'close',
code: 1
}), '*')
主页面接收数据
// index.html
window.addEventListener('message', function (e) {
try {
let data = JSON.parse(e.data)
if (data.from === 'auth' && data.event === 'close') {
authIframe.style.display = 'none'
}
} catch (error) {
console.log(error)
}
})
主页面向iframe传参
主页面发送数据
在iframe加载完成后再发送数据
// index.html
let authIframe = document.getElementById('authIframe')
let params = {
id: 1213
}
authIframe.addEventListener('load', function (e) {
authIframe.contentWindow.postMessage(JSON.stringify(params), 'https://pc.xunlei.com')
})
iframe接收参数
// iframe
let params = {}
window.addEventListener('message', function (event) {
params = JSON.parse(event.data);
})
总结
发送数据用postMessage
,接收数据是监听message
事件:element.addEventListener('message', callback)