postmessage是唯一通用且安全的跨域通信方式,它通过浏览器提供的受控消息通道实现父子页面双向通信,要求发送方指定目标源、接收方严格校验event.origin以防范恶意消息。

直接访问 contentWindow 或 window.parent 必然报错
浏览器同源策略下,只要协议、域名、端口任一不同,iframe.contentWindow、window.parent、window.top 就会返回一个被“冻结”的 window 对象——多数属性读取时抛出 SecurityError: Blocked a frame with origin "xxx" from accessing a cross-origin frame。这不是权限没开,是浏览器硬性拦截,任何 try-catch 都捕获不到具体属性访问错误,只会在控制台显式报错。
postMessage 是唯一通用且安全的跨域通信方式
它不绕过同源策略,而是由浏览器提供受控通道,必须双方主动配合才能通信。关键点不是“怎么发”,而是“怎么收 + 怎么验”:
- 子页面发消息必须带明确目标源,不能只写
'*'(开发调试可临时用,上线必须指定父页完整协议+域名+端口,如'https://myapp.com') - 父页面监听
message事件时,必须校验e.origin,否则可能接收恶意站点伪造的消息 -
e.data可以是字符串或结构化对象(自动序列化),但不要传函数、DOM 节点等无法克隆的值 - IE8/9 仅部分支持,若需兼容,得降级用
document.domain(仅限同主域不同子域场景)
示例(父页):
window.addEventListener('message', (e) => {
if (e.origin !== 'https://child.example.com') return;
console.log('收到子页数据:', e.data);
// 处理逻辑
});子页:window.parent.postMessage({ action: 'resize', height: 600 }, 'https://parent.example.com');
为什么 document.domain 不总能用
它只在「同主域、不同二级域名」时有效(如 a.example.com 和 b.example.com),且要求父子页都显式设置相同值:
document.domain = 'example.com';一旦涉及协议不同(HTTP vs HTTPS)、端口不同(8080 vs 80)、或完全无关域名(
qq.com vs taobao.com),该方法直接失效,还会引发其他脚本错误。现在很多项目默认强制 HTTPS,这个方案实际适用范围很窄。
代理页面方案容易被忽略的坑
当子页无法改代码(比如嵌第三方系统),只能靠父页加一层同源代理页(如 /proxy.html)中转时,要注意:
- 代理页必须与父页同源,且不能被 CSP 策略禁止执行内联脚本
- 代理页加载后需立即调用
window.top.xxx(),但此时window.top可能还没挂载好目标方法,需加轮询或 Promise 化等待 - 代理页本身不能有跨域资源请求(如外链 CSS/JS),否则自身加载失败会导致整条链路中断
- 每次通信都要新建 iframe,频繁操作会造成内存泄漏,需手动
remove()
这个方案本质是把跨域问题转成同源问题,但维护成本高、调试链路长,除非完全无法控制子页,否则优先选 postMessage。
postMessage,而是确保两端约定的 origin 值精确匹配——少一个 https://、多一个末尾斜杠、端口漏写,都会静默失败。线上环境尤其要核对部署后的实际 URL,别只信本地 localhost 测试结果。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











