Skip to content

参考:四机制速查 / 安全清单 / 选型

基于 WHATWG HTML(跨文档消息 / 通道消息 / 广播频道)现行标准与各浏览器 Baseline 状态 · 核于 2026-07

速查

  • 四机制window.postMessage(跨源点对点)· MessageChannel/MessagePort(私有双向管道 + 端口转移)· BroadcastChannel(同源一对多广播)· Web Locks(协调 / 选主,非传消息)。
  • postMessage 发目标window.postMessage(msg, targetOrigin, transfer?)targetOrigin 精确写对方源、别用 * 传敏感数据
  • postMessage 收window.addEventListener("message", e => ...)先校验 e.origin(头号安全点)再校验 e.data 结构;e.source 回复用、非身份;e.ports 取转移来的 port。
  • MessageChannelconst { port1, port2 } = new MessageChannel()port.postMessage(d, transfer?) / port.onmessageaddEventListener 必须 port.start()onmessage= 隐式 start
  • 端口转移window:transfer 是第三参数;Worker:transfer 是第二参数;对端从 event.ports[0] 取;转移后原 port 失效(neutered)
  • BroadcastChannelnew BroadcastChannel("名")bc.postMessage(d)同源同分区不回发给自己无 sender 标识bc.close()
  • Web Locksnavigator.locks.request(name, opts?, cb);锁在回调返回时释放回调返 永不 resolve 的 Promise = 一直持有(选主)
  • Web Locks optsmodeexclusive 默认 / shared)、ifAvailable(拿不到不等、回调收 null)、steal(抢占)、signalAbortSignal 超时)。
  • 能传什么:postMessage / port / BroadcastChannel 均结构化克隆(函数 / DOM 节点不可);postMessage 与 port 支持 transfer 零拷贝,BroadcastChannel 不支持 transfer
  • 跨源:只有 postMessage 能跨源;MessageChannel 随宿主(可转移到跨源 <iframe>);BroadcastChannel / Web Locks 仅同源
  • Baseline:postMessage / 通道消息 2015 起;BroadcastChannel / Web Locks 2022-03 起(Web Locks 仅 HTTPS 安全上下文)。
  • 多标签同步:首选 BroadcastChannel;老浏览器兜底 storage 事件;共享状态 / 长连接用 SharedWorker;已用 SW 可 clients.matchAll() 转发。
  • 多标签选主:Web Locks 竞选唯一 leader + BroadcastChannel 分发结果 = 黄金搭档;异常关闭自动释放锁、follower 补位。
  • 头号坑三连:postMessage 不校验 origin(安全)/ MessagePortstart()(收不到)/ 选主回调提前返回(leader 秒卸任)。
  • 相邻叶只链接:storage 事件 → Web Storage 叶SharedWorkerWeb Workers 叶;Service Worker → Service Worker 叶

一、四机制全景

机制规范拓扑跨源传输典型用途
window.postMessageWHATWG HTML · Web messaging点对点(窗口 ↔ 窗口 / <iframe> / 弹窗 / Worker)结构化克隆 + transfer与第三方 <iframe> / window.open 弹窗通信
MessageChannel / MessagePortWHATWG HTML · Channel messaging点对点专属管道(端口可转移)随宿主结构化克隆 + transfer(含转移 port)私有双向通道、Worker 直连、RPC 底座
BroadcastChannelWHATWG HTML · Broadcasting一对多广播仅同源同分区结构化克隆(无 transfer多标签同步:登出 / 主题 / 数据失效
Web LocksW3C Web Locks API协调 / 选主(不传数据)仅同源——多标签选主、互斥、读写者

二、window.postMessage 速查

说明
发送目标window.postMessage(message, targetOrigin, transfer?)postMessage(message, { targetOrigin, transfer })
message结构化克隆;函数 / DOM 节点 / 类方法不可(DataCloneError
targetOrigin接收方须匹配的源(scheme+host+port 全等);省略默认 "/"(同源);data: 等不透明源须 "*"
transferTransferable 列表(ArrayBuffer / MessagePort / ImageBitmap …)零拷贝移交,移交后本地失效
接收window.addEventListener("message", handler)
event.data数据副本
event.origin发送窗口的源——唯一可信身份依据
event.source发送窗口引用——回复用event.source.postMessage(...)),非身份
event.ports随消息转移来的 MessagePort 数组

目标窗口引用来源iframe.contentWindow(父→子)、window.open() 返回值(主→弹窗)、window.opener(弹窗→主)、window.frames[i]window.parent / window.topevent.source(回复)。

三、postMessage 安全清单

  • 发送端targetOrigin 精确写对方源,绝不用 * 传敏感数据(恶意站点可改窗口位置截获);只有 data: / 不透明源不得已才 *,且不传敏感数据。
  • 接收端第一行if (event.origin !== 期望源) return;——非白名单一律丢弃;不接收外站消息就干脆别挂 message 监听(最彻底)。
  • 验完来源再验结构:校验 event.data 的类型 / 形状 / 字段,别把它塞进 innerHTML / eval / new Function——否则被信任站点的 XSS 传染成你的 XSS。
  • event.source 只当回信地址:身份永远看 origin,不拿 source 当认证。
  • 回复用 event.source.postMessage(data, event.origin)origin 回填 targetOrigin,天然打回正确对端。
  • <iframe> 握手:父页面等 <iframe> load 再发首条,或让子框架先发 ready,避免消息丢失。
  • SharedArrayBuffer 跨源:需 Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corpcrossOriginIsolated === true

四、MessagePort 方法与事件

成员说明
postMessage(message, transfer?)经该端口发消息;targetOrigin;支持 transfer(含再转移 port)
start()启用端口消息队列;addEventListener 时必须显式调用onmessage= 赋值时隐式调用
close()断开端口、停止收发、利于回收
onmessage / message 事件收消息,数据在 event.data;赋 onmessage 隐式 start()
onmessageerror / messageerror 事件收到无法反序列化(结构化克隆失败)的消息

start() 判定表

监听方式是否需手动 start()
port.onmessage = fn(隐式启用队列)
port.addEventListener("message", fn)port.start(),否则一条都收不到且不报错)

端口转移规则MessagePort 是 Transferable;window.postMessage(msg, targetOrigin, [port])(第三参数)或 worker.postMessage(msg, [port])(第二参数)转移;对端 event.ports[0] 取;转移后原持有者立即 neutered;可多次接力转移,同一时刻仅一个活跃持有者。

五、BroadcastChannel 速查

成员说明
new BroadcastChannel(name)连接 / 创建同名频道;参数仅频道名
postMessage(data)广播给同源同分区所有其他订阅者;结构化克隆;无 transfer
onmessage / message 事件收广播,数据在 event.data
onmessageerror / messageerror 事件收到无法反序列化的消息
close()断开与频道的连接、允许回收
name只读,频道名

两条定义性特征:① 发送者收不到自己发的消息(WHATWG「Remove source from destinations」)——本页要立即生效的状态须自己手动应用再广播;② 消息无发送者标识、无语义——payload 自带 type / senderId范围:仅同源且同存储分区。

六、Web Locks 速查

API说明
navigator.locks.request(name, cb)请求锁;拿到后调 cb(lock)cb 返回(或其 Promise resolve)时释放
navigator.locks.request(name, options, cb)带选项版
navigator.locks.query()返回锁状态快照 { held, pending }(name / mode / clientId),调试用
选项取值 / 含义
mode"exclusive"(默认,同名仅一个持有)/ "shared"(可多个同时持有,读写者的「读」)
ifAvailabletrue:不能立即授予就不排队cbnull 调用
stealtrue:释放同名已持有锁并抢占授予、绕过排队(慎用,会打断原持有者)
signalAbortSignal:中止锁请求,配 setTimeout 做超时(中止时 reject AbortError

选主范式request(name, cb)cb 返回 new Promise(() => {})(永不 resolve)= 一直持锁 = 一直是 leader;本页关闭 / 崩溃锁自动释放,排队者补位。限制:仅安全上下文(HTTPS,localhost 视作安全)+ Worker;作用域限同源。

七、机制对比

维度postMessageMessageChannelBroadcastChannelWeb Locks
拓扑点对点点对点专线一对多广播协调 / 选主
跨源随宿主❌ 仅同源❌ 仅同源
收自己发的视对端视对端❌ 不回发——
传数据克隆 + transfer克隆 + transfer克隆(无 transfer)不传数据
需校验来源origin转移那次需同源天然——
招牌坑不校验 originstart()以为收自己发的回调提前返回丢 leader
Baseline2015 起2015-09 起2022-03 起2022-03 起(HTTPS)

八、多标签页选型

需求首选备选 / 兜底
同步状态(登出 / 主题 / 数据失效)BroadcastChannelstorage 事件(老浏览器)· SW 转发(已用 SW)
共享一份状态 / 一条长连接SharedWorkerWeb Locks 选主 + 普通 Worker + 广播
只让一个标签页干活(连 WS / 轮询 / 同步)Web Locks 选主——
选主 + 把成果发给全体Web Locks + BroadcastChannelSharedWorker 集中 + 广播
跨源(<iframe> / 弹窗)传数据postMessagepostMessage + MessageChannel 建专线

九、易错点清单

  • postMessage targetOrigin* 传敏感数据:可被截获——写死对方源。
  • 接收端不校验 event.origin:任何窗口都能发消息——第一行 if (event.origin !== 期望源) return;
  • event.data 直接进 innerHTML / eval:XSS 传染——校验结构 + 白名单 / 转义。
  • event.source 当身份:只是回信地址——身份看 origin
  • <iframe>load 就发消息:监听未就绪、丢失——等 loadready 握手。
  • MessagePortaddEventListenerport.start():一条都收不到、不报错——补 start() 或改 onmessage=
  • 转移后仍用原 port / ArrayBuffer:已 neutered / byteLength 0——转移前发完,转移后用新宿主的。
  • 对端不从 event.ports[0] 取 port:port 不在 data 里——在 ports
  • port.postMessagetargetOrigin:port 版第二参数是 transfer——targetOrigin 只属 window.postMessage
  • 以为 BroadcastChannel 收自己发的:不会——本页状态自己手动应用再广播。
  • BroadcastChannel 消息不带 type / senderId:无语义无身份——payload 自带。
  • 指望 BroadcastChannel 跨源 / 到没开的页 / transfer 大对象:仅同源存活上下文、无 transfer——跨源用 postMessage、持久化用存储、大对象用点对点。
  • 选主回调写成会返回的 async:锁一释放 leader 秒卸任——返回永不 resolve 的 Promise。
  • 自造 localStorage 心跳锁做选主:时钟 / 死锁 / 僵尸持有者——用 Web Locks(异常自动释放)。
  • HTTP 页用 Web Locks:仅安全上下文——线上 HTTPS(localhost 例外)。
  • 滥用 Web Locks steal:打断原持有者临界区——仅确诊卡死时用。
  • 用 storage 事件当通用广播:只字符串、写入页不触发、要读回值——新项目用 BroadcastChannel

十、权威链接