如何通过Chrome调试器API在内联脚本的document.write处断点并记录参数
问题描述
我有一个包含内联脚本<script>document.write("bla")</script>的页面,想要开发Chrome扩展记录document.write的参数“bla”。原本计划使用Chrome调试器API,但代码并未触发断点。
相关代码如下:
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { if (changeInfo.status === 'complete' && tab.url && !tab.url.startsWith('chrome://')) { attachDebugger(tab.id); } }); function attachDebugger(debuggeeTabId) { chrome.debugger.attach({tabId:debuggeeTabId}, "1.0", function() { if (chrome.runtime.lastError) { console.log(chrome.runtime.lastError.message); return; } // Enable the Debugger chrome.debugger.sendCommand({tabId:debuggeeTabId}, "Debugger.enable", {}, function() { if (chrome.runtime.lastError) { console.log(chrome.runtime.lastError.message); return; } chrome.debugger.sendCommand({tabId:debuggeeTabId}, "DOM.enable", {}, function() { if (chrome.runtime.lastError) { console.log(chrome.runtime.lastError.message); return; } // Set the breakpoint chrome.debugger.sendCommand({tabId:debuggeeTabId}, "DOMDebugger.setInstrumentationBreakpoint", {eventName: "document.write"}, function() { if (chrome.runtime.lastError) { console.log(chrome.runtime.lastError.message); return; } console.log("Breakpoint set on document.write"); }); }); }); }); chrome.debugger.onEvent.addListener(debuggerEvent); } function debuggerEvent(debuggeeId, message, params) { console.log(message + " " + JSON.stringify(params)); //let callFrame = params.callFrames[0]; //let funcArgs = callFrame.scopeChain[0].object.description; //console.log("document.write called with arguments: ", funcArgs); }
Chrome DevTools中有“EventListener Breakpoint - Parse - document.write”的断点选项,但不清楚实现方式;尝试使用DOMDebugger.setEventListenerBreakpoint也未成功。
解决方案
核心问题分析
原代码失效的关键原因是时机不对:tabs.onUpdated的complete状态在页面所有资源加载完成后触发,但内联的document.write在HTML解析阶段就已经执行完毕,此时再附加调试器、设置断点,根本无法捕获到目标调用。
修正后的代码
1. 背景脚本(background.js)
// 改用webNavigation.onCommitted事件,在页面开始加载时触发 chrome.webNavigation.onCommitted.addListener((details) => { const tabId = details.tabId; chrome.tabs.get(tabId, (tab) => { if (tab.url && !tab.url.startsWith('chrome://')) { attachDebugger(tabId); } }); }); function attachDebugger(debuggeeTabId) { chrome.debugger.attach({tabId: debuggeeTabId}, "1.0", () => { if (chrome.runtime.lastError) { console.log(chrome.runtime.lastError.message); return; } // 启用Debugger chrome.debugger.sendCommand({tabId: debuggeeTabId}, "Debugger.enable", {}, () => { if (chrome.runtime.lastError) { console.log(chrome.runtime.lastError.message); return; } // 启用DOMDebugger(无需启用DOM,此处不需要) chrome.debugger.sendCommand({tabId: debuggeeTabId}, "DOMDebugger.enable", {}, () => { if (chrome.runtime.lastError) { console.log(chrome.runtime.lastError.message); return; } // 设置document.write的 instrumentation breakpoint chrome.debugger.sendCommand( {tabId: debuggeeTabId}, "DOMDebugger.setInstrumentationBreakpoint", {eventName: "document.write"}, () => { if (chrome.runtime.lastError) { console.log(chrome.runtime.lastError.message); return; } console.log("已设置document.write断点"); } ); }); }); }); // 先移除旧监听,避免重复绑定导致多次输出 chrome.debugger.onEvent.removeListener(debuggerEvent); chrome.debugger.onEvent.addListener(debuggerEvent); } function debuggerEvent(debuggeeId, message, params) { // 监听instrumentation断点触发事件 if (message === "DOMDebugger.instrumentationBreakpointHit") { // 获取document.write的调用栈帧 const callFrame = params.callFrames[0]; // 提取第一个参数值 if (callFrame.arguments.length > 0) { const writeParam = callFrame.arguments[0].value; console.log("document.write调用参数:", writeParam); } } }
2. 清单文件(manifest.json)
需要添加webNavigation权限确保能捕获页面加载事件:
{ "name": "Document Write 日志记录器", "version": "1.0", "permissions": ["debugger", "tabs", "webNavigation"], "background": { "service_worker": "background.js" }, "manifest_version": 3 }
关键改动说明
- 事件替换:用
chrome.webNavigation.onCommitted替代tabs.onUpdated,确保在页面解析HTML前完成调试器附加和断点设置。 - 事件监听优化:每次附加调试器前先移除旧的
debuggerEvent监听,避免重复绑定导致多次输出。 - 参数提取逻辑:在
DOMDebugger.instrumentationBreakpointHit事件中,通过callFrames获取调用栈,直接从arguments中提取document.write的传入参数。
内容的提问来源于stack exchange,提问作者joe-jeff
相关产品推荐
相关产品推荐

