iframe跨域时无法访问contentWindow是同源策略强制保护,须用postMessage配合源校验实现安全通信,document.domain已废弃。
当用 嵌入不同源(协议、域名、端口任一不同)的页面时,浏览器会阻止脚本访问 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 看似简单,但实际常因细节失效。常见卡点:
iframe 加载完成就调用 postMessage —— 应监听 iframe.onload 或 DOMContentLoaded 后再发
event.origin !== 'https://trusted.com' 校验,导致被恶意页面冒充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 字符串iframe.contentDocument.body.scrollHeight —— 如果嵌入页 CSS 有 height: 100% 或 position: fixed 元素,这个值可能不准;更稳妥的是由嵌入页 JS 主动上报过去可通过设置 document.domain = 'example.com' 让 a.example.com 和 b.example.com 跨域变同源。但 HTML5 中该方式已被废弃:
document.domain 的支持(仅保留读取,写入抛错)example.com ↔ other-site.net)无效postMessage,兼容性更好、语义更清晰、权限控制更细现在还看到 document.domain 相关代码,基本可以判定是遗留系统,升级时应优先替换为 postMessage 协作模型。
跨域通信真正难的不是语法,而是两边约定好消息格式、错误重试逻辑、超时兜底和源校验粒度 —— 这些往往比写几行 postMessage 花的时间多得多。