JavaScript中如何读取新打开window对象的跨域控制台输出?
核心限制说明
浏览器同源策略禁止你操作跨域打开的窗口的任何全局属性、DOM或者事件,你目前写的newWindow.addEventListener在跨域场景下直接会抛出权限错误,根本无法执行,更不可能监听控制台输出。
以下两种方案均针对你调试自有项目的场景实现需求:
方案1:同域代理(无需修改目标项目代码)
如果你不想改动待调试的项目代码,就给你的简易日志站加一个简单的反向代理功能,把待调试的项目地址代理到和日志站同域名的路径下,比如:
- 你的日志站是
http://localhost:3000 - 代理配置把
/proxy/我的项目转发到你待调试的项目地址http://xxx.xxx
这样你打开的新窗口地址就是同域的http://localhost:3000/proxy/我的项目,不存在跨域限制,就可以直接劫持控制台输出了。
同域下的日志收集示例代码
const newWindow = window.open('/proxy/我的项目') // 等新窗口加载完成后重写console方法 newWindow.onload = () => { const originalConsole = newWindow.console const outputEl = document.getElementById('output') // 重写所有console方法 ;['log', 'warn', 'error', 'info', 'debug'].forEach(method => { const originalMethod = originalConsole[method] originalConsole[method] = (...args) => { // 先执行原始的console逻辑 originalMethod.apply(originalConsole, args) // 输出到当前页的DOM const logText = `[${method}] ${args.map(arg => typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)).join(' ')}\n` outputEl.textContent += logText } }) // 监听全局错误 newWindow.addEventListener('error', e => { outputEl.textContent += `[全局错误] ${e.message} 位于 ${e.filename}:${e.lineno}:${e.colno}\n` }) // 监听未处理的Promise rejection newWindow.addEventListener('unhandledrejection', e => { outputEl.textContent += `[Promise未捕获异常] ${e.reason}\n` }) }
方案2:跨域PostMessage上报(无需后端代理)
如果你没法加代理,且可以修改待调试的项目代码,直接在待调试项目里加一段日志上报脚本,把所有控制台输出通过postMessage发送到你的日志站即可:
待调试项目里加的脚本
// 替换成你的日志站的地址 const LOG_COLLECTOR_ORIGIN = 'http://你的日志站地址' const originalConsole = window.console ;['log', 'warn', 'error', 'info', 'debug'].forEach(method => { const originalMethod = originalConsole[method] originalConsole[method] = (...args) => { originalMethod.apply(originalConsole, args) window.opener?.postMessage({ type: 'console', method, args: args.map(arg => typeof arg === 'object' ? JSON.parse(JSON.stringify(arg)) : arg) }, LOG_COLLECTOR_ORIGIN) } }) // 全局错误上报 window.addEventListener('error', e => { window.opener?.postMessage({ type: 'error', message: e.message, filename: e.filename, line: e.lineno, col: e.colno }, LOG_COLLECTOR_ORIGIN) }) window.addEventListener('unhandledrejection', e => { window.opener?.postMessage({ type: 'unhandledrejection', reason: e.reason }, LOG_COLLECTOR_ORIGIN) })
日志站的接收代码
const newWindow = window.open('https://你待调试的项目地址') const outputEl = document.getElementById('output') // 监听跨域消息 window.addEventListener('message', e => { // 校验来源是你待调试的项目的地址,避免恶意消息 if (e.origin !== 'https://你待调试的项目地址') return const data = e.data let logText = '' switch(data.type) { case 'console': logText = `[${data.method}] ${data.args.map(arg => typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)).join(' ')}\n` break case 'error': logText = `[全局错误] ${data.message} 位于 ${data.filename}:${data.line}:${data.col}\n` break case 'unhandledrejection': logText = `[Promise未捕获异常] ${data.reason}\n` break } outputEl.textContent += logText })
内容的提问来源于stack exchange,提问作者Nolan Carpenter
相关产品推荐
相关产品推荐

