postMessage 跨域通信
使用 window.postMessage 实现跨域窗口通信
问题
如何在不同源的窗口(如 iframe)之间安全地传递消息?
解答
什么是 postMessage
window.postMessage() 方法提供了一种受控的跨源通信机制。它可以安全地在不同源的窗口之间传递数据,只要正确使用就很安全。
语法
otherWindow.postMessage(message, targetOrigin, [transfer]);
参数说明:
message: 要发送的数据targetOrigin: 目标窗口的源,如"https://example.org"transfer: 可选,传递的对象所有权
接收消息的事件对象
window.addEventListener('message', function(event) {
// event.data - 传递过来的数据
// event.origin - 发送方的源(协议 + 域名 + 端口)
// event.source - 发送方窗口的引用
});
使用示例
子框架发送消息:
// 子框架向父框架发送消息
function sendToParent(msg) {
var parentUrl = window.parent.location.origin;
window.parent.postMessage(msg, parentUrl);
}
window.onload = function() {
sendToParent('Hello from iframe');
}
父框架接收消息:
window.addEventListener('message', function(e) {
// 验证来源
if (e.origin !== 'http://example.com:8080') {
return;
}
console.log('收到消息:', e.data);
console.log('来自:', e.origin);
});
双向通信示例
A 窗口(发送方):
// A窗口域名: http://example.com:8080
var popup = window.open('http://example.org/popup.html');
// 等待弹窗加载完成后发送消息
popup.postMessage(
"The user is 'bob' and the password is 'secret'",
"http://example.org" // 必须指定精确的目标源
);
B 窗口(接收方):
// B窗口域名: http://example.org
function receiveMessage(event) {
// 验证消息来源
if (event.origin !== "http://example.com:8080") {
return;
}
// 处理消息
console.log('接收到的数据:', event.data);
// 可以通过 event.source 回复消息
event.source.postMessage('收到消息', event.origin);
}
window.addEventListener('message', receiveMessage);
安全注意事项
1. 始终验证消息来源:
window.addEventListener('message', function(event) {
// 检查 origin
if (event.origin !== 'https://trusted-site.com') {
return; // 拒绝不信任的来源
}
// 验证消息格式
if (typeof event.data !== 'object' || !event.data.type) {
return;
}
// 处理消息
});
2. 指定精确的 targetOrigin:
// ❌ 不安全 - 任何窗口都能接收
otherWindow.postMessage(data, '*');
// ✅ 安全 - 只有指定源能接收
otherWindow.postMessage(data, 'https://example.com');
关键点
postMessage用于不同源窗口之间的安全通信,常见于 iframe、弹窗等场景- 发送消息时必须指定精确的
targetOrigin,避免使用'*' - 接收消息时必须验证
event.origin,拒绝不信任的来源 - 接收到的数据也需要验证格式和内容,防止 XSS 攻击
- 可以通过
event.source实现双向通信
目录