Chrome扩展程序用于读取HTTP响应

18
我有一个Chrome扩展程序,可以在发送请求前修改请求头。现在我想要在同一个扩展程序中检查响应头。我在Chrome扩展API中搜索过,但没有找到任何有用的信息。
这是我用于修改请求头的代码,也许对您知道如何做有所帮助。
chrome.webRequest.onBeforeSendHeaders.addListener(
      function(details) {/*do something*/},
      {urls: ["<all_urls>"]},
      ["blocking", "requestHeaders"]);

有人知道如何做到这一点,或者能指引我到一个有趣的资源吗?谢谢


我目前正在寻找一个Chrome扩展程序(我不知道如何编写自己的),它可以修改响应头。具体来说,我想动态更改_Content-Type_ image/x-pngimage/png,因为Chrome不理解x-png(早期的一个bug,仍未修复)。您是否成功创建了您的扩展程序?如果是,它能够满足我的需求吗? - kriegaex
更新:Chrome扩展程序“Redirector”可以满足我的需求。谢谢。 - kriegaex
2个回答

46

我通过向DOM注入脚本,成功捕获了网站发出的所有HTTP请求和响应。根据您的需求和环境,有几种不同的方法可以实现这一功能,例如ManifestV3/V2。以下是我使用的方法:

inject.js:

var s = document.createElement('script');
// must be listed in web_accessible_resources in manifest.json
s.src = chrome.runtime.getURL('injected.js');
s.onload = function() {
    this.remove();
};
(document.head || document.documentElement).appendChild(s);

这将在匹配 manifest.json 中 "content_scripts" "matches" 的网站中注入 injected.js。在 "js" 中提到了 contentscript.js 和 inject.js。 请参见答案末尾的 manifest.json。

现在,injected.js 中实际捕获请求和响应的代码受到 如何使用 Chrome 扩展程序从网站选项卡中捕获 AJAX 请求 的启发。还请查看该文章的评论部分。

injected.js:

(function(xhr) {

    var XHR = XMLHttpRequest.prototype;

    var open = XHR.open;
    var send = XHR.send;
    var setRequestHeader = XHR.setRequestHeader;

    XHR.open = function(method, url) {
        this._method = method;
        this._url = url;
        this._requestHeaders = {};
        this._startTime = (new Date()).toISOString();

        return open.apply(this, arguments);
    };

    XHR.setRequestHeader = function(header, value) {
        this._requestHeaders[header] = value;
        return setRequestHeader.apply(this, arguments);
    };

    XHR.send = function(postData) {

        this.addEventListener('load', function() {
            var endTime = (new Date()).toISOString();

            var myUrl = this._url ? this._url.toLowerCase() : this._url;
            if(myUrl) {

                if (postData) {
                    if (typeof postData === 'string') {
                        try {
                            // here you get the REQUEST HEADERS, in JSON format, so you can also use JSON.parse
                            this._requestHeaders = postData;    
                        } catch(err) {
                            console.log('Request Header JSON decode failed, transfer_encoding field could be base64');
                            console.log(err);
                        }
                    } else if (typeof postData === 'object' || typeof postData === 'array' || typeof postData === 'number' || typeof postData === 'boolean') {
                            // do something if you need
                    }
                }

                // here you get the RESPONSE HEADERS
                var responseHeaders = this.getAllResponseHeaders();

                if ( this.responseType != 'blob' && this.responseText) {
                    // responseText is string or null
                    try {

                        // here you get RESPONSE TEXT (BODY), in JSON format, so you can use JSON.parse
                        var arr = this.responseText;

                        // printing url, request headers, response headers, response body, to console

                        console.log(this._url);
                        console.log(JSON.parse(this._requestHeaders));
                        console.log(responseHeaders);
                        console.log(JSON.parse(arr));                        

                    } catch(err) {
                        console.log("Error in responseType try catch");
                        console.log(err);
                    }
                }

            }
        });

        return send.apply(this, arguments);
    };

})(XMLHttpRequest);

manifest.json:

{
  "manifest_version": 3,
  "name": "Extension Name",
  "description": "Some Desc.",
  "version": "1.1",
  "content_scripts": [{
      "matches": ["*://website.com/*"],
      "run_at": "document_start",
      "js": ["contentscript.js", "inject.js"]
  }],
  "web_accessible_resources": [{
      "resources": ["injected.js"],
      "matches": ["*://website.com/*"]
  }]
}

对于MV2,最后一个块只需写成"web_accessible_resources": ["injected.js"]


1
@user5155835 谢谢,那么现在 contentscript.js 是什么?你能帮我看看这里吗:https://dev59.com/UK7la4cB1Zd3GeqPkuWV?noredirect=1#comment92268497_52669328?谢谢。 - Nammen8
1
@user5155835 那个 contentscript.js 文件怎么样? - Er KK Chopra
@ErKKChopra 这里是链接:https://dev59.com/UK7la4cB1Zd3GeqPkuWV#52699831 - user5155835
@user5155835 这能在最新的 Manifest V3 中运行吗?因为他们有一些关于内联 JavaScript 的限制。 - Andrew
1
谢谢!这很有帮助,但我纠正了一些问题并简化了它。以下是我的更改摘要,并附上完整示例的链接:https://dev59.com/NWw15IYBdhLWcg3wGn5c#67390377 - Justin Harris
显示剩余7条评论

1

1
或者,如果您正在使用Web请求API,您可以在修改标头时记录requestId,然后在onHeadersReceived事件中检查该requestId。 - PAEz
我在尝试做同样的事情,只是看到live-headers示例后,我不知道该怎么做。 - fiatjaf
同样的问题,如果有人能帮忙处理Web请求API,那就太好了。 - Vitali Pom
链接已失效。 - OroshiX
1
@OroshiX - 已修复 - A T
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接