postMessage 是 HTML5 提供的跨文档消息传递 API,它允许不同源的窗口之间安全地进行通信,包括 iframe 与父页面之间的通信。
基本语法
javascript// 发送消息 otherWindow.postMessage(message, targetOrigin, [transfer]); // 接收消息 window.addEventListener('message', (event) => { // 处理消息 });
参数说明
- message: 要发送的数据,可以是任何可序列化的对象
- targetOrigin: 目标窗口的源,可以是具体的 URL、"*"(所有源)或 "/"(同源)
- transfer: 可选,用于转移所有权的一组可转移对象
安全最佳实践
1. 始终验证消息来源
javascriptwindow.addEventListener('message', (event) => { // 验证消息来源 if (event.origin !== 'https://trusted-domain.com') { return; } // 处理消息 const data = event.data; });
2. 使用具体的 targetOrigin
javascript// 不推荐:允许所有源 iframe.postMessage(data, '*'); // 推荐:指定具体源 iframe.postMessage(data, 'https://trusted-domain.com');
3. 验证消息数据格式
javascriptwindow.addEventListener('message', (event) => { if (event.origin !== 'https://trusted-domain.com') { return; } // 验证数据结构 if (!event.data || typeof event.data.type !== 'string') { return; } switch (event.data.type) { case 'resize': handleResize(event.data); break; case 'close': handleClose(); break; } });
iframe 与父页面通信示例
父页面发送消息到 iframe
javascriptconst iframe = document.getElementById('myIframe'); // 等待 iframe 加载完成 iframe.onload = () => { iframe.postMessage({ type: 'init', data: { userId: 123, token: 'abc123' } }, 'https://child-domain.com'); };
iframe 发送消息到父页面
javascript// iframe 内部代码 window.parent.postMessage({ type: 'resize', data: { width: 800, height: 600 } }, 'https://parent-domain.com');
父页面接收 iframe 消息
javascriptwindow.addEventListener('message', (event) => { if (event.origin !== 'https://child-domain.com') { return; } if (event.data.type === 'resize') { const iframe = document.getElementById('myIframe'); iframe.style.width = event.data.data.width + 'px'; iframe.style.height = event.data.data.height + 'px'; } });
常见应用场景
- 跨域通信: 不同域名下的页面之间进行数据交换
- 第三方集成: 嵌入第三方服务(如支付、登录)时的状态同步
- 响应式调整: iframe 内容根据自身尺寸通知父页面调整
- 单点登录: 在不同域之间传递认证信息
- 实时数据更新: 子页面向父页面推送实时数据
注意事项
- 同源策略限制: postMessage 不受同源策略限制,但需要正确设置 targetOrigin
- 消息序列化: 发送的数据会被结构化克隆,某些对象(如函数、DOM 节点)无法发送
- 性能考虑: 频繁的消息传递可能影响性能,建议批量处理或使用防抖
- 错误处理: 添加适当的错误处理机制,防止恶意消息导致安全问题