postMessage是HTML5提供的唯一标准化跨域跨窗口通信API,基于异步消息事件机制,需严格校验targetOrigin和event.origin以保障安全,支持结构化数据传输但须注意兼容性与生命周期管理。

postMessage 是唯一能真正支撑跨窗口通信的机制,HTML 本身没有“通信能力”——<script> 标签、<iframe> 属性或任何 HTML 元素都不具备发送/接收消息的逻辑。所谓“HTML通信”是常见误解,实际起效的是 JavaScript 的 window.postMessage() API。
为什么直接写 parent.postMessage() 会报错?
常见错误现象:Uncaught TypeError: parent.postMessage is not a function 或 Blocked a frame with origin ... from accessing a cross-origin frame
- 目标窗口(比如弹窗或 iframe)尚未加载完成,
parent/opener/contentWindow指向的是空或受限对象 - 调用方试图在非同源上下文中直接访问
parent.location或opener.document,触发浏览器同源策略拦截 - 没等
load事件就调用postMessage,尤其在 iframe 场景下,iframe.contentWindow可能存在但不可信
postMessage 的 origin 参数为什么不能总写 "*"?
虽然 "*" 看起来省事,但它会带来两个实际风险:
- 如果页面被嵌入恶意 iframe,或你打开了不受控的新窗口,
"*"会让任意源都能收到你的敏感数据(比如 token、用户 ID) - 部分企业内网或安全加固环境(如 Chrome 扩展策略、CSP
connect-src)会直接屏蔽postMessage到"*"的调用,导致静默失败 - 正确做法是显式指定目标源,例如
"https://app.example.com";若需兼容同协议同主机不同端口(如 localhost:3000 ↔ localhost:8080),可只传"http://localhost"(注意协议必须匹配)
接收消息时为什么 e.data 有时是字符串、有时是对象?
这是浏览器兼容性与序列化习惯共同导致的:
- 规范允许
data传任意可结构化克隆的对象(Array、Object、Date 等),但 IE10–IE11 和部分旧版 Safari 仅支持字符串 - 如果你在发端用了
JSON.stringify(obj),收端就必须JSON.parse(e.data);反之若直接传对象,某些老环境会转成"[object Object]" - 更稳妥的做法:统一走字符串序列化,并在接收端加
try...catch防止解析失败:window.addEventListener('message', e => { let data; try { data = typeof e.data === 'string' ? JSON.parse(e.data) : e.data; } catch (err) { console.warn('Invalid message format', e.data); return; } // 后续处理 });
postMessage 就认为对方一定收到了——需要设计超时、重试或确认机制,尤其在登录跳转、支付回调这类关键路径上。



















