通过window.onmessage设置iframe的src后3秒变空白的原因及解决办法
问题原因
- 未校验消息来源:你当前的
window.onmessage监听没有对消息发送方的来源(event.origin)做校验,iframe加载的第三方页面本身也可能向父窗口发送postMessage消息,3秒后刚好触发了这类消息,传入的非预期event.data覆盖了原本正确的iframe地址 - 未校验消息内容格式:只要
event.data存在就直接修改iframe的src,没有判断内容是否为合法URL,也没有和当前iframe已加载的地址做去重判断,如果后续收到非URL类型的有效值(比如对象、数字等),赋值给src后就会导致页面加载失败出现黑屏
你可以先在onmessage逻辑开头加console.log('收到消息', event.origin, event.data),打开控制台就能直接看到3秒后触发的异常消息的来源和具体内容。
解决方案
- 增加消息来源校验,只接收你信任的外部触发方域名的消息,屏蔽iframe内部页面发送的无关消息
- 增加消息内容校验,确认传入的内容是合法URL后再修改iframe地址,也可以约定固定的消息格式,避免非预期消息触发修改逻辑
- 新增地址去重判断,如果要设置的地址和当前iframe已加载的地址一致,就不重复赋值,避免不必要的重加载
修改后的核心代码示例
<!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8"> <link rel="mask-icon" href="https://assets-cdn.github.com/pinned-octocat.svg" color="#000000"> <link rel="icon" type="image/x-icon" href="https://assets-cdn.github.com/favicon.ico"> <link rel="shortcut icon" type="image/x-icon" href="https://assets-cdn.github.com/favicon.ico"> <style> body { background: #232323; width: 95%; margin: 0 auto; } /* Responsive Container for iFrame */ .embed-container { position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%; } .embed-container iframe, .embed-container object, .embed-container embed { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } </style> <title>Tech Ops PH | your < IT / design < partner </title> <script type="text/javascript"> window.onmessage = (event) => { // 替换成你外部按钮所在页面的实际域名,本地调试可以填http://localhost:对应端口 const ALLOWED_ORIGIN = 'https://你的可信域名.com'; // 非可信来源的消息直接拦截 if (event.origin !== ALLOWED_ORIGIN) return; // 校验传入内容是否为合法URL let targetSrc = ''; try { targetSrc = new URL(event.data).href; } catch (e) { return; } // 地址相同就不重复赋值,避免无效重加载 const iframe = document.getElementById("myIframe"); if (iframe.src !== targetSrc) { iframe.src = targetSrc; } } </script> </head> <body> <div class='embed-container embed-responsive embed-responsive-4by3'> <iframe id="myIframe" width="600" height="9000" frameborder="0" style="border:0" allowfullscreen></iframe> </div> </body> </html>
内容的提问来源于stack exchange,提问作者idan
相关产品推荐
相关产品推荐

