如何将内层iframe的高度传递给其父级iframe?
解决跨域iframe嵌套下postMessage的CORS拦截问题
问题根源
你用window.top.frames[1].postMessage报错,核心原因是window.top指向的是内网域名intranet.domain.com,它的frames集合属于内网域;而你的内层Widget部署在cdn.domain.com,跨域情况下根本无法获取其他域的frame对象引用,浏览器的同源策略直接拦截了这个操作,这和postMessage本身的origin限制无关。
解决方案
既然生成器和Widget同属cdn.domain.com,完全可以让Widget只和自己的直接父级(生成器iframe)通信,再由生成器处理高度设置或转发消息,全程规避跨域访问frame的问题:
1. 修改内层Widget代码
去掉访问window.top.frames[1]的逻辑,只向直接父级发送消息:
function iframeHeightHandler() { let height = document.body.scrollHeight; // 只向直接父级(生成器iframe,同域)发送消息,指定明确origin更安全 window.parent.postMessage(["setHeight", height], "https://cdn.domain.com"); console.log('msg sent: '+ height + 'px' +' (iframe.js)'); } window.addEventListener('load', iframeHeightHandler); window.addEventListener('resize', iframeHeightHandler);
2. 修改生成器iframe代码
生成器作为Widget的直接父级,收到消息后可以直接修改Widget iframe的高度(同域无DOM操作限制),如果需要同步给内网top窗口,再转发一次消息:
// 假设生成器里的Widget iframe有明确选择器,比如#widget-iframe const widgetIframe = document.getElementById('widget-iframe'); window.addEventListener('message', function(e) { const eventName = e.data[0]; const data = e.data[1]; const origin = e.origin; // 只接受同域Widget的消息 if (origin !== 'https://cdn.domain.com') { console.log('origin not allowed'); return; } switch(eventName) { case 'setHeight': // 直接修改Widget iframe的高度(同域无限制) widgetIframe.style.height = `${data}px`; // 如果需要让内网top窗口也收到高度信息,再转发给top window.top.postMessage(["setHeight", data], "https://intranet.domain.com"); console.log('message received & processed: '+ data + 'px' +' (embed.js)'); break; } }, false);
关键注意事项
- 跨域场景下,永远不要尝试直接访问其他域的
window.frames或iframe.contentWindow,同源策略会直接拦截这类操作。 - 利用同域中间层(这里的生成器iframe)做消息中转,是嵌套iframe跨域通信的标准方案。
- postMessage务必指定明确的目标origin,不要用
*,避免安全风险。
内容的提问来源于stack exchange,提问作者Julian W.
相关产品推荐
相关产品推荐

