HTML通信本质是JavaScript跨执行上下文传数据,涉及window、iframe、popup、tab及Web Worker;postMessage是唯一通用安全方案,需校验origin;同源可直访属性或共享存储;跨tab需BroadcastChannel等中介。

HTML通信不等于跨窗口通信
HTML本身没有“通信”能力,所谓HTML通信其实是JavaScript在不同执行上下文之间传递数据的行为。浏览器里能形成独立执行上下文的常见场景包括:同源/跨源的window、iframe、popup、tab,以及Web Worker。只要不是同一个window对象,就涉及跨上下文——但“跨窗口”只是其中一种情况,不是前提。
postMessage是跨上下文通信的事实标准
postMessage是唯一被所有现代浏览器支持的、安全可控的跨上下文通信机制。它不要求同源,但要求接收方主动监听并校验event.origin或event.source,否则有XSS风险。
常见错误现象:
- 发了消息但对方收不到:没在目标
window上绑定message事件,或监听时机太晚(比如iframe还没加载完成) - 收到
event.data是undefined:发送时传入了不可序列化的值(如函数、DOM节点、Promise) - 消息被恶意站点截获:没检查
event.origin !== 'https://trusted.com'
示例(父页向iframe发消息):
立即学习“前端免费学习笔记(深入)”;
const iframe = document.querySelector('iframe');
iframe.contentWindow.postMessage({ type: 'INIT', payload: 42 }, 'https://example.com');
对应iframe内需监听:
window.addEventListener('message', (e) => {
if (e.origin !== 'https://parent.com') return;
console.log(e.data); // { type: 'INIT', payload: 42 }
});
同源页面间可用更轻量的方式
如果两个页面同源(协议+域名+端口完全一致),可以直接访问对方的window对象属性或调用函数,无需postMessage:
- 父页调用子
iframe方法:iframe.contentWindow.doSomething() - 子
iframe访问父页变量:window.parent.someGlobalVar - 共享
localStorage或sessionStorage(注意触发storage事件仅在其他同源窗口中生效)
但要注意:这些方式在跨源时会直接抛出SecurityError,且无法用于popup或新tab(除非显式保留引用,如const w = window.open(...))。
跨tab通信需要借助中介存储
浏览器禁止window对象跨tab直接引用,所以postMessage无法直接用于不同tab之间。常用折中方案是利用共享存储作为“广播站”:
-
localStorage+storage事件:一个tab写,其他同源tab监听到变更 -
BroadcastChannelAPI(Chrome 66+/Firefox 61+):更干净,但IE和旧Safari不支持 - Service Worker +
clients.matchAll():适合PWA场景,控制力强但接入成本高
BroadcastChannel示例:
const bc = new BroadcastChannel('my_channel');
bc.postMessage({ type: 'SYNC' });
bc.addEventListener('message', e => console.log(e.data));
注意:该API在iframe中可用,但若页面被嵌入跨源iframe,则可能因COOP/COEP策略被禁用。
真正容易被忽略的是:跨上下文通信从来不是“连上就能通”,而是要逐层确认——目标是否存在、是否加载完成、是否同源、是否允许访问、是否监听了正确事件、是否做了来源校验。漏掉任何一环,消息就消失在黑盒里。



















