五、使用 PostMessage 的跨窗口通信(用于临时或有限场景)
通过浏览器 window.postMessage
API 在不同窗口间安全传递 Token。
同源窗口(协议、域名、端口一致)之间可以自由通信,无需指定 targetOrigin
。
非同源窗口(跨域)必须通过 postMessage
明确指定目标的 targetOrigin
,并验证消息来源。
浏览器对单次传递的消息内容有大小限制(通常为 5-6MB)。超过限制时,消息可能被截断或直接失败。解决方案:分批次发送大数据,或使用二进制格式(如 ArrayBuffer
)。
如果目标窗口已关闭或不存在,postMessage
会静默失败,不会触发错误。
即使设置了 targetOrigin
,接收方仍需通过 event.origin
验证发送者身份,防止中间人攻击。
// 发送方
window.postMessage(message, targetOrigin, [transfer]);
// 参数:
// message:要发送的数据(支持对象、字符串、可序列化的类型)
// targetOrigin:目标窗口的源(如 "https://example.com" 或 "*" 表示任何来源)
// transfer:可选,用于转移对象所有权(如 ArrayBuffer)
// 接收方
window.addEventListener('message', function(event) {
// 验证来源
if (event.origin !== 'https://trusted.origin.com') return; // 只接收指定来源
// 处理消息
console.log(event.data); // 消息内容
});
场景说明:
- 当用户在两个不同域名的应用间跳转时,通过新开标签页传递 Token。
- 例如:应用A登录后,通过弹出窗口告知应用B用户已登录。
实现步骤:
-
应用A在登录后向应用B发送消息:
// 应用A:
const otherWindow = window.open('https://appB.com/message', '_blank');
otherWindow.postMessage(
{ type: 'login', token: 'your_jtw_token' },
'https://appB.com'
);
2.应用B监听消息并验证 Token:
// 应用B:
window.addEventListener('message', (event) => {
if (event.origin !== 'https://appA.com') return; // 验证来源安全
if (event.data.type === 'login') {
const token = event.data.token;
// 验证 Token 后存储到本地
localStorage.setItem('user_token', token);
}
});