postMessage是iframe跨域通信唯一可靠方案,需严格校验origin与targetOrigin、加载完成后发送、仅传可序列化数据,且CORS对其无效。

iframe 嵌套中的跨域通信不能靠绕过同源策略,必须走浏览器允许的协作通道。核心思路是:不直接读 DOM,改用消息机制;不强求单向控制,而是双方约定协议、校验来源、结构化传值。
postMessage 是唯一可靠且通用的方案
这是 HTML5 标准 API,支持任意跨域场景(不同协议、域名、端口),也是现代项目首选。
- 父页面发消息给 iframe:
iframe.contentWindow.postMessage(data, targetOrigin),targetOrigin 必须写具体域名(如'https://example.com'),禁用'*'生产环境 - iframe 内监听:
window.addEventListener('message', handler),收到后必须检查event.origin是否可信,再处理event.data - 双向通信需约定字段,比如用
{ type: 'INIT', payload: {...} }区分指令类型,避免字符串硬匹配出错 - iframe 页面加载完成后,应主动向父页发就绪信号(如
{ type: 'READY' }),父页收到后再发送业务指令
不要混淆 CORS 和 iframe 跨域通信
CORS 是为 fetch/XMLHttpRequest 设计的服务器响应头机制,它对 iframe 的 DOM 访问或 postMessage 完全无效。你在 iframe 的 src 地址上加 CORS 头,不会让 contentDocument 变得可读——那是两个不同层面的问题。
- 如果你控制 iframe 内容,想让它发起跨域请求(比如调用后端 API),那才需要服务端配
Access-Control-Allow-Origin - 如果你只是嵌入第三方 iframe(如支付页、地图组件),你无法改它的后端响应头,这时只能依赖它是否暴露
postMessage接口 - 代理转发(如 Nginx 把
/proxy/pay映射到https://pay.third.com)可让 iframe 同源加载,从而启用直取 DOM,但这要求你有服务端权限且能统一部署路径
其他辅助方案适用场景有限
它们不是 postMessage 的替代品,而是在特定约束下“退而求其次”的选择:
立即学习“Java免费学习笔记(深入)”;
-
document.domain:仅适用于父子同主域但子域不同(如
a.example.com和b.example.com),双方都设document.domain = 'example.com'后可直取 DOM;不适用于跨主域、HTTPS/HTTP 混合等场景 -
URL hash:适合单向、轻量、低频传递(如跳转标识、简单状态码),靠监听
hashchange事件触发,数据长度受限、无类型、易被覆盖 - window.name:利用其在页面跳转后仍保留的特性,适合中转大量文本数据(如 JSON 字符串),但需额外中转页配合,流程复杂,现代项目已较少使用
安全与健壮性关键细节
很多通信失败不是因为不会写,而是忽略校验和容错:
- 接收方永远不要信任
event.source,必须结合event.origin白名单判断来源是否合法 - 消息体只传可序列化数据(对象、数组、字符串、数字),不要传函数、DOM 节点、Date 实例等,否则会静默丢失
- iframe 加载未完成时调用
postMessage会报错,建议用iframe.onload或iframe.contentWindow?.postMessage加空值判断 - 若 iframe 来自不可控第三方,先确认它是否监听
message并响应;否则所有发送都是单向丢包


















