页面嵌套跨域通信方式 postMessage
一个窗口可以获得对另一个窗口的引用(比如 targetWindow = window.opener),然后在窗口上调用 targetWindow.postMessage() 方法分发一个 MessageEvent 消息。接收消息的窗口可以根据需要自由处理此事件(en-US)。传递给 window.postMessage() 的参数(比如 message)将通过消息事件对象暴露给接收消息的窗口。
语法
postMessage(message, targetOrigin, [transfer]);
message:
将要发送到其他 window 的数据。它将会被结构化克隆算法(en-US)序列化。
targetOrigin:
通过窗口的 origin 属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个 URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配 targetOrigin 提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。
*如果明确的知道消息应该发送到哪个窗口,那么要始终提供一个有确切值的 targetOrigin,而不是 。
transfer:
是一串和 message 同时传递的 Transferable 对象。这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
父窗口中使用
function IframeBox () {
const ifm = useRef<HTMLIFrameElement>(null);
const messageHandle = (event: MessageEvent) => {
if (event.origin === "http://localhost:5173") {
// 设置精确的域名
console.log("父窗口收到消息:" + event.data);
}
};
useEffect(() => {
console.log("ifm", ifm);
// postMessage通信
window.addEventListener("message", messageHandle);
const timer = setInterval(function () {
// 每隔1s向子窗口发送消息
if (ifm.current) {
ifm.current.contentWindow?.postMessage(
'hello', // message
"http://localhost:5173"
);
}
}, 1000);
return () => {
clearInterval(timer);
window.removeEventListener("message", messageHandle);
};
});
return (
<>
iframe
<div onClick={() => navigate('/home')}>goback</div>
<iframe ref={ifm} src="http://localhost:5173/" id="iframe1"></iframe>
</>
);
}
子窗口使用
// 获取父窗口
const parentWindow = window.parent;
// postMessage通信
window.addEventListener('message', function (event) {
if (event.origin === "http://localhost:3000") { // 设置精确的域名
console.log('子窗口收到消息:' + event.data);
parentWindow.postMessage('I received it', 'http://localhost:3000');
}
});
安全问题
- 如果不希望从其他网站接收 message,不要为 message 事件添加任何事件侦听器。
- 如果希望从其他网站接收 message,始终使用 origin 和 source 属性验证发件人的身份