Chrome MV3扩展拦截修改HTTP响应时无法捕获全部请求的原因排查
问题描述
我正在开发一款可修改网络请求响应内容的Chrome扩展,前期调研时参考了Stack Overflow的相关实现方案,并将方案集成到了自己的扩展中。
调试脚本时发现,现有实现可以检测到大部分请求,但无法覆盖全部请求,需要重点拦截的核心请求恰好未被捕获,需排查导致该问题的可能原因。
现有实现代码
manifest.json
{ "manifest_version": 3, "permissions": [ "tabs" ], "web_accessible_resources": [{ "resources": ["script.js"], "matches": [ "<all_urls>" ] }], "action": { "default_popup": "index.html" }, "content_scripts": [ { "matches": [ "<all_urls>" ], "js": ["jquery-3.6.0.min.js", "contentscript.js"], "run_at": "document_start" } ] }
contentscript.js
var s = document.createElement('script'); s.src = chrome.runtime.getURL('script.js'); s.onload = function() { this.remove(); }; (document.head || document.documentElement).appendChild(s);
script.js
var _open = XMLHttpRequest.prototype.open; window.XMLHttpRequest.prototype.open = function (method, URL) { var _onreadystatechange = this.onreadystatechange, _this = this; _this.onreadystatechange = function () { // catch only completed 'api/search/universal' requests try { console.log('Caught! :)', method, URL/*, _this.responseText*/); } catch (e) {} if (_this.readyState === 4 && _this.status === 200 && ~URL.indexOf('api/search/universal')) { try { ////////////////////////////////////// // THIS IS ACTIONS FOR YOUR REQUEST // // EXAMPLE: // ////////////////////////////////////// var data = JSON.parse(_this.responseText); // {"fields": ["a","b"]} if (data.fields) { data.fields.push('c','d'); } // rewrite responseText Object.defineProperty(_this, 'responseText', {value: JSON.stringify(data)}); /////////////// END ////////////////// } catch (e) {} } // call original callback if (_onreadystatechange) _onreadystatechange.apply(this, arguments); }; // detect any onreadystatechange changing Object.defineProperty(this, "onreadystatechange", { get: function () { return _onreadystatechange; }, set: function (value) { _onreadystatechange = value; } }); return _open.apply(_this, arguments); };
可能的故障原因
- 脚本注入存在竞态:虽然content script配置了
document_start时机运行,但你注入到页面上下文的script.js是通过动态创建script标签加载的,属于异步加载资源。如果目标页面的核心请求由极早期执行的内联脚本发起(比如HTML最开头的script块直接调用XHR),此时你的hook代码还没加载完成,原生方法没被改写,请求自然不会被捕获。 - 仅拦截了XMLHttpRequest,未覆盖fetch请求:目前多数站点的核心接口会优先使用fetch API发起,你的代码只改写了XMLHttpRequest的原型方法,完全没有对fetch做hook,所有走fetch的请求都不会被检测到。
- XHR响应监听逻辑覆盖不全:你只劫持了onreadystatechange属性赋值的场景,如果页面是通过
addEventListener('readystatechange')、addEventListener('load')、addEventListener('loadend')等事件监听方式接收响应,你的自定义逻辑不会触发,自然捕获不到对应请求。 - 内容安全策略(CSP)拦截:如果目标站点配置了严格的CSP规则,禁止加载非同源脚本,你动态注入的
script.js会被直接拦截无法执行,所有hook逻辑都不会生效。 - 过滤规则存在遗漏:你的代码只有在请求
readyState ===4且status ===200、URL包含api/search/universal时才会进入处理逻辑:如果核心请求走本地缓存返回304、或者接口路径存在版本前缀、大小写差异、参数全部放在请求体中URL不包含匹配字段,都会被过滤规则漏掉。 - 页面提前缓存了原生方法:部分站点的请求工具库、前端框架会在页面加载的最早期就把原生XMLHttpRequest、fetch的引用缓存到私有变量里,你后续修改原型对象的操作不会影响已经缓存的原生方法引用,这类库发起的请求不会经过你改写的逻辑。
内容的提问来源于stack exchange,提问作者nitruseq
相关产品推荐
相关产品推荐

