postmessage发送消息必须指定准确targetorigin,否则浏览器静默丢弃;接收方须校验event.origin并比对event.source,不可仅依赖message监听。

postMessage 发送消息时必须指定准确的 targetOrigin
不填或填 "*" 虽然能发出去,但浏览器会直接丢弃——尤其在 iframe 加载完成前就调用、或目标页面重定向后 origin 变更时。真实场景中,targetOrigin 必须与 iframe 当前 contentWindow.location.origin 严格一致(协议 + 域名 + 端口)。可先监听 load 事件,再读取 iframe.contentWindow?.location?.origin;若无法预知目标域,至少应设为具体域名,例如 "https://example.com",而不是 "https://*" 或空字符串。
常见错误现象:Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('*') does not match the recipient window's origin —— 这不是警告,是静默失败,控制台可能无提示,消息根本没发出去。
接收端必须校验 event.origin 并检查 event.source
仅靠监听 message 事件远远不够。恶意页面可能伪造 postMessage,所以每次收到消息都得做两件事:验证 event.origin 是否在白名单内,确认 event.source 是预期的 iframe 窗口引用(比如和你保存的 iframe.contentWindow 相等)。漏掉任一检查,就可能被钓鱼页面劫持通信。
实操建议:
- 用
Set或数组维护可信 origin 列表,避免硬编码字符串比较 - 发送方首次通信可附带
type: "handshake"和随机nonce,接收方回传确认,建立双向信任 - 不要依赖
event.data里的自定义字段做权限判断,origin 和 source 才是唯一可信依据
iframe 未加载完成就调用 postMessage 会报错或无效
iframe.contentWindow 在 DOM 插入后立即可访问,但其内部 JS 环境尚未初始化,此时调用 postMessage 会抛出 TypeError: Cannot read property 'postMessage' of null(如果 iframe src 为空或非法),或静默失败(如果 src 已设但未加载完)。
可靠做法是监听 iframe 的 load 事件,且在回调中再次确认 iframe.contentWindow 存在、iframe.contentWindow.location.origin 可读:
iframe.addEventListener("load", () => {
if (iframe.contentWindow && iframe.contentWindow.location?.origin) {
iframe.contentWindow.postMessage(data, iframe.contentWindow.location.origin);
}
});
注意:Safari 对跨域 iframe 的 location.origin 访问限制更严,部分版本返回 "null",此时需配合服务端 header(如 Access-Control-Allow-Origin)或改用 window.name 协助识别。
消息序列化限制与大体积数据传输陷阱
postMessage 底层使用结构化克隆算法(structured clone),不支持函数、undefined、Symbol、循环引用对象、DOM 节点等。传 JSON.stringify 后再解析是多余操作,反而增加开销;直接传 plain object 即可。
但要注意:
- 超过几 MB 的数据(如 base64 图片、大型数组)会导致主线程卡顿,Chrome 有隐式大小限制(约 10–20MB),超出可能被截断或触发
SecurityError - 频繁发送小消息(如每秒几十次)会堆积事件队列,接收端应做节流或合并处理
- 如需双向流式通信,建议封装成简单协议:加
id字段用于响应匹配,用type区分请求/响应/错误
真正难处理的不是怎么发,而是怎么确保对方收到了、处理完了、有没有重试机制——这些都得自己补全,postMessage 本身不提供 ACK 或超时。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











