iframe跨域时无法访问contentWindow是同源策略强制保护,须用postMessage配合源校验实现安全通信,document.domain已废弃。

iframe 跨域时无法访问 contentWindow
当用 嵌入不同源(协议、域名、端口任一不同)的页面时,浏览器会阻止脚本访问 iframe.contentWindow 或 iframe.contentDocument,直接报错 Blocked a frame with origin "https://a.com" from accessing a cross-origin frame.。这不是 bug,是浏览器同源策略的强制保护。
解决思路不是“绕过”策略,而是通过合法通信机制协作:
- 双方页面都需主动配合,不能单边修改
- 主页面调用
window.postMessage()发送消息,嵌入页监听message事件接收 - 嵌入页回复时也必须指定目标源(
event.source.postMessage(..., event.origin)),不能写*(除非你明确信任所有来源) - 主页面监听自身
message事件时,务必校验event.origin和event.source,防止伪造消息
postMessage 传参和响应不生效?检查这几点
postMessage 看似简单,但实际常因细节失效。常见卡点:
- 发送方未等
iframe加载完成就调用postMessage—— 应监听iframe.onload或DOMContentLoaded后再发 - 接收方没加
event.origin !== 'https://trusted.com'校验,导致被恶意页面冒充 - 发送数据含函数、DOM 节点等无法序列化的值,会静默失败 —— 只能传可 JSON 序列化的对象
- 嵌入页在 iframe 内调用
parent.postMessage,但主页面绑定了错误的事件监听器(比如绑在window上却忘了加useCapture: false默认行为,其实不影响)
示例(主页面发):
iframe.addEventListener('load', () => {
iframe.contentWindow.postMessage({ type: 'INIT', data: { theme: 'dark' } }, 'https://embed.example.com');
});
嵌入页想主动通知主页面高度变化,怎么安全传?
这是典型场景:嵌入页内容动态撑高,需要通知父页调整 iframe 高度。关键在于避免无限循环和 XSS 风险:
立即学习“前端免费学习笔记(深入)”;
- 嵌入页每次调用
parent.postMessage({ type: 'RESIZE', height: 520 }, parentOrigin)前,先确认parentOrigin是白名单中的源(如从初始化消息里记下) - 主页面收到后,只更新
iframe.style.height,**不要**直接执行eval()或插入 HTML 字符串 - 若嵌入页高度频繁变动,建议加防抖(如 100ms 内只发最后一次)
- 别依赖
iframe.contentDocument.body.scrollHeight—— 如果嵌入页 CSS 有height: 100%或position: fixed元素,这个值可能不准;更稳妥的是由嵌入页 JS 主动上报
为什么 document.domain 不再适用?
过去可通过设置 document.domain = 'example.com' 让 a.example.com 和 b.example.com 跨域变同源。但 HTML5 中该方式已被废弃:
- Chrome 85+、Firefox 79+ 已完全移除对
document.domain的支持(仅保留读取,写入抛错) - 即使旧版浏览器可用,它也只适用于**同主域子域间**,对完全不同的域名(如
example.com↔other-site.net)无效 - 现代方案统一用
postMessage,兼容性更好、语义更清晰、权限控制更细
现在还看到 document.domain 相关代码,基本可以判定是遗留系统,升级时应优先替换为 postMessage 协作模型。
跨域通信真正难的不是语法,而是两边约定好消息格式、错误重试逻辑、超时兜底和源校验粒度 —— 这些往往比写几行 postMessage 花的时间多得多。










