前端-通信机制
2026年1月21日 16:02
业务开发中,通信可能会涉及到同源与跨域的场景,Web开发中,同源策略(协议+域名+端口一致)是保障用户信息安全的核心机制。但业务中常需实现页面间通信,本文提供了三种主流方案:同源高效的BroadcastChannel、基于StorageEvent的跨标签页同步、跨域安全的postMessage。
一、BroadcastChannel:同源页面间的广播站
核心特性
- 严格遵循同源策略,不同源页面自动隔离
发布-订阅模式,一对多通信- 频道名称在同源内唯一,跨页面同名频道自动关联
代码示例
// 页面A(商品详情页)
const productChannel = new BroadcastChannel('product_updates');
productChannel.postMessage({
type: 'PRICE_UPDATE',
data: { sku: 'SKU-123', price: 199 }
});
// 页面B(购物车页面)
const cartChannel = new BroadcastChannel('product_updates');
cartChannel.addEventListener('message', (e) => {
if (e.data.type === 'PRICE_UPDATE') {
updateCartItem(e.data.data.sku, e.data.data.price);
}
});
关键要点
- 必须使用
new BroadcastChannel(channelName)创建同名频道 - 消息建议包含
type字段作为标识符,便于接收方路由处理 - 浏览器自动管理连接,无需手动维护窗口引用
二、StorageEvent:跨标签页的状态同步
触发条件
- 必须由不同标签页/窗口触发
- 必须通过
localStorage.setItem()/removeItem()/clear()修改 - 同一标签页内的修改不会触发事件
代码示例
// 页面A(主题设置页)
document.getElementById('theme-btn').addEventListener('click', () => {
const darkMode = !JSON.parse(localStorage.getItem('darkMode'));
localStorage.setItem('darkMode', JSON.stringify(darkMode)); // 触发事件
});
// 页面B(所有页面)
window.addEventListener('storage', (e) => {
if (e.key === 'darkMode') {
applyTheme(JSON.parse(e.newValue));
}
});
调试技巧
- 使用
window.open()打开测试窗口确保同源 - 在控制台检查
e.url确认触发来源 - 避免使用
sessionStorage(仅当前标签页有效)
三、跨域通信:postMessage实践
示例代码
// 父页面(https://main.com)
const iframe = document.createElement('iframe');
iframe.src = 'https://trusted-subdomain.com/widget';
document.body.appendChild(iframe);
// iframe.contentWindow,子页面window发送事件
iframe.contentWindow.postMessage({
type: 'INIT_WIDGET',
apiKey: 'ABC123'
}, 'https://trusted-subdomain.com');
// 父页面监听子页面e.source.postMessage
window.addEventListener('message', (e) => {
});
// iframe页面(https://trusted-subdomain.com),子页面监听
window.addEventListener('message', (e) => {
if (e.origin !== 'https://main.com') return;
if (e.data.type === 'INIT_WIDGET') {
initWidget(e.data.apiKey);
// e.source父页面的windowd对象
e.source.postMessage({ status: 'READY' }, e.origin);
}
});
以上代码是基于iframe嵌套的跨域页面实现的,也可以基于windowNew = window.open(url),即多个window跨域窗口通信,本质上获取window对象是关键
安全要点
- 永远不要使用
targetOrigin: '*'(生产环境) - 消息数据应包含类型字段便于路由
- 使用
e.source而非直接操作window.opener - 敏感数据需加密传输