Chrome调试器Network.getResponseBody报-32000资源未找到错误求助
我正在开发一款从浏览器游戏中抓取数据的Chrome扩展,使用Chrome Debugger API附加调试器,监听标签页与服务器的所有交互消息。流程是:先监听目标URL对应的Network.responseReceived事件,再等待同一requestId的Network.loadingFinished事件触发,之后调用Network.getResponseBody命令获取响应体并处理存储。
近期随机出现错误:{"code":-32000,"message":"No resource with given identifier found"},成功率约50%,且每次都能拿到正确的requestId。
已尝试的解决方法
- 在
Network.loadingFinished事件触发前调用Network.getResponseBody - 收到
loadingFinished事件后立即发送命令 - 失败后按指数递增延迟重试
- 使用不同固定延迟发送命令
补充排查信息
排查游戏交互消息发现:
- 触发-32000错误时,必然缺失交互的前3条消息
- 成功请求的
Network.responseReceived事件中hasExtraInfo字段为true,失败请求则为false
疑问
如果Network.enable命令是在Network.requestWillBeSent事件触发后才执行的,调用Network.getResponseBody是不是一定会失败?我之前以为只要requestId有效就能正常工作。
相关代码
const maxRetryAttempts = 5; // 获取指定requestId的响应体 async function GetRewardResponseBody(debuggeeId, params, responseReceivedEpoch) { var errorArray = []; var initialDelayMS = 5; var fetchSucceeded = false; for(let retryAttempts = 1; retryAttempts <= maxRetryAttempts; retryAttempts++){ await sendCommandPromise(debuggeeId.tabId, params) .then((response) => { ProcessRewardJSON(debuggeeId.tabId, response); // 未触发-32000错误时处理数据 console.log("成功退出,debuggeeId: ", debuggeeId); fetchSucceeded = true; }).catch((error) => { // 捕获错误 errorArray.push(error); }); if (fetchSucceeded){break;} // 成功则跳出循环 await delay(initialDelayMS); // 等待后重试 initialDelayMS *= 2; } if (!fetchSucceeded){ console.log(errorArray); // 打印所有错误 } console.log("清除超时并返回"); clearTimeout(debuggerTimeout); // 移除自动卸载调试器的超时 RemoveDebugger(debuggeeId, false); } function sendCommandPromise(tabId, params) { return new Promise((resolve, reject) => { try{ chrome.debugger.sendCommand( {"tabId" : tabId }, "Network.getResponseBody", { "requestId": params.requestId }, function(response) { if (chrome.runtime.lastError){ // 捕获-32000错误 reject(chrome.runtime.lastError); } else if (!response || !response.body) { // 响应体为空的情况 console.error("响应体为空"); reject(new Error("响应体为空")); } else {resolve(response);} }); } catch(ex){ // 其他异常 console.log("获取资源出错"); reject(ex) } }); } function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
核心问题根源
你遇到的-32000错误,核心原因就是**Network.enable执行时机晚于目标请求的requestWillBeSent事件**。Chrome Debugger API的Network模块只有在Network.enable生效后,才会开始记录请求的完整数据(包括响应体)。如果请求已经开始甚至完成后才开启Network监控,调试器根本没存储这个请求的响应体数据,就算requestId能通过后续事件拿到,调用getResponseBody也会提示找不到资源。
从你补充的排查信息也能佐证这一点:失败请求的responseReceived事件中hasExtraInfo为false,说明调试器没有捕获到该请求的完整上下文;同时缺失前3条交互消息,正好对应调试器启动前已经发出的请求。
针对性修复方案
确保
Network.enable在页面加载/请求发起前执行- 不要等到页面已经开始加载游戏内容才附加调试器,应该在标签页刚创建(
chrome.tabs.onCreated)或即将导航(chrome.webNavigation.onBeforeNavigate)时就附加调试器并立即调用Network.enable。 - 如果是针对已打开的标签页,附加调试器后先调用
Network.enable,再刷新页面,确保所有请求都在监控范围内。
- 不要等到页面已经开始加载游戏内容才附加调试器,应该在标签页刚创建(
优化事件监听逻辑
- 不要只依赖
responseReceived+loadingFinished的组合,建议同时监听Network.requestWillBeSent,提前记录目标URL的requestId,确保调试器从请求一开始就跟踪它。 - 对于
hasExtraInfo为false的responseReceived事件,直接跳过后续的getResponseBody调用,避免无效重试。
- 不要只依赖
调整重试策略
- 当前的指数退避重试对这种“调试器根本没存储数据”的情况无效,因为资源本身就不存在,重试多少次都没用。应该在第一次失败且确认是
-32000错误时,直接判断是监控时机问题,触发页面刷新或重新附加调试器的逻辑,而不是继续重试。
- 当前的指数退避重试对这种“调试器根本没存储数据”的情况无效,因为资源本身就不存在,重试多少次都没用。应该在第一次失败且确认是
代码调整建议
修改GetRewardResponseBody中的错误处理逻辑,识别-32000错误后直接终止重试:
// 在catch分支中添加判断 .catch((error) => { errorArray.push(error); // 识别-32000错误,直接终止重试 if (error.code === -32000) { console.log("监控时机过晚,请求未被调试器记录"); fetchSucceeded = false; retryAttempts = maxRetryAttempts; // 强制跳出循环 } });
同时,在附加调试器的逻辑中,确保先调用Network.enable:
async function attachDebugger(tabId) { await chrome.debugger.attach({tabId: tabId}, "1.3"); // 立即启用Network监控 await chrome.debugger.sendCommand({tabId: tabId}, "Network.enable"); // 然后再添加事件监听 chrome.debugger.onEvent.addListener(handleDebuggerEvent); }
内容的提问来源于stack exchange,提问作者granbluetracker

