问题描述
在主页面内部点击按钮,通过Iframe打开另一个的页面,两个页面完全是不一样的工程,主页面使用的框架时React,弹窗嵌入页面使用的框架时Vue,两这个通过PostMessage进行消息传递。因此在实际开发过程中,如果想要在本地调试嵌入式页面,需要在控制台中,使用window.postMessage向页面发送信息或者在页面使用mock数据,才能正常调试。但是在排查问题和本地调试,尤其是真线问题的时候,无法准确的获得主页面使用postMessage发送的具体数据,进行本地测试,如果通过接口自己mock数据,可能会出现偏差,导致本地没有问题,但是发上去就有问题,严重影响开发效率和测试回归效率。
目前的浏览器插件,只能支持监听主页面的也就是顶层window的postMessage数据,不能支持监听签入iframe页面的window对象的postMessage数据,针对此问题,我们开发了一个浏览器插件 ,可以获取到内部iframe页面发送的postMessage数据,可以准确获取到mock数据,帮助本地调试。
基础知识
🚀PostMessage
父窗口想通过postMessage向子窗口发送数据,需要获取到iframe的window对象
子窗口想通过postMessage向父窗口发送数据,需要获取到iframe的window对象
upStarOrGuarantee = (item, isUpStar, renewal, guaranteeCode) => {
setTimeout(() => {
const iFrame = document.getElementById("inlineFrameExample");
iFrame?.contentWindow?.postMessage?.(params, "*");
this.setState({
loading: false,
});
}, 2000);
};
<iframe>
id="inlineFrameExample"
title="Inline Frame Example"
width="980"
height="560"
src={`${window.envHref.middle}/luban/guarantee/component`}
/>
window.addEventListener('message', (event) => {
if (event.origin === 'https://yourdomain.com') {
console.log('Received:', event.data);
} else {
console.warn('Untrusted origin:', event.origin);
}
});
🚀浏览器插件
核心配置:manifest.json,插件运行在独立的环境中,与网页环境隔离开来,可以通过content.js与页面交互。
{
"manifest_version": 2,
"name": "Sample Extension",
"version": "1.0",
"description": "A simple browser extension example.",
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
//插件需要的权限,例如访问特定域名、使用浏览器的某些功能(如tabs、cookies等)。
"permissions": [
"" ,
"https://*.example.com/*"
],
"browser_action": {
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"default_popup": "popup.html",
"default_title": "Sample Extension"
},
//后台脚本,这些脚本在插件加载时运行,通常用于处理长期任务或者事件监听
"background": {
"scripts": ["background.js"],
"persistent": false
},
//配置内容脚本,这些脚本注入到匹配的网页中,并可以与网页内容交互
"content_scripts": [
{
//字段指定匹配的URL模式,控制注入的页面
"matches": ["https://*.example.com/*"],
//js调本
"js": ["content.js"],
//css脚本
"css": ["styles.css"],
//运行的时机
"run_at": "document_idle",
//是否注入所有的iframe
"all_frames": true
}
],
//声明插件中的哪些资源(如图像、脚本等)可以被网页访问。
"web_accessible_resources": [
"images/*"
],
//配置插件的选项页面,用户可以在此页面中配置插件的设置。
"options_page": "options.html"
}
解 决方案
🤔️方案1:获取到iframe的contentwinow监听message方法,在控制台打印数据获取到的数据
const iFrame = document.getElementById("inlineFrameExample");
iFrame?.contentWindow?.addEventListener("message", (e) => {
console.log(e);
});
❌结果:不可行,父窗口不打开弹框的情况下,获取不到Iframe对象,无法监听postMessage,触发函数也是异步获取的。在控制台,异步监听也会报错,会出现同源问题,如下所示。
setTimeout(() => {
const iFrame = document.getElementById("inlineFrameExample");
iFrame?.contentWindow?.addEventListener("message", (e) => {
console.log(e);
});
}, 15000);
// VM218:3 Uncaught DOMException: Failed to read a named property 'addEventListener' from 'Window': Blocked a frame with origin "https://agreement.test.zcygov.cn" from accessing a cross-origin frame.
// at :3:24
// (anonymous) @ VM218:3
🤔️方案2:使用浏览器插件,通过浏览器插件,将配置内容脚本注入到所有的Iframe中,通过window对象监听postEvent事件,并打印数据。✅
📃创建【manifest.json】,确保插件有足够的权限,访问目标域名,并配置内容脚本到所有的iframe中。
{
"manifest_version": 2,
"name": "Print Iframe Scripts and Variables",
"version": "1.0",
"permissions": [
""
],
"content_scripts": [
{
"matches": [""],
"js": ["content.js"],
"all_frames": true,
"run_at": "document_idle"
}
]
}
📃创建【content.js】,在内容脚本中注入javaScript,并监听iframe的postMessage事件
/** @format */
(function () {
// Check if the script is running in an iframe
if (window !== window.top) {
try {
console.log('window is not the top window', window);
window.addEventListener('message', e => {
console.log('window.event', e);
console.log('window.data', e.data.data);
console.log('window.msgType', e.data.msgType);
});
} catch (error) {
console.error('Error accessing iframe content:', error);
}
}
})();