You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 17:54:30