【问题标题】:Modify HTTP responses from a Chrome extension修改来自 Chrome 扩展的 HTTP 响应
【发布时间】:2013-08-19 09:26:50
【问题描述】:

是否可以创建修改 HTTP 响应正文的 Chrome 扩展程序?

我已经查看了Chrome Extension APIs,但我没有找到任何可以执行此操作的操作。

【问题讨论】:

标签: google-chrome-extension overriding httpresponse


【解决方案1】:

通常,您不能使用标准 Chrome 扩展 API 更改 HTTP 请求的响应正文。

正在104058: WebRequest API: allow extension to edit response body 申请此功能。为问题加注星标以获取更新通知。

如果您想编辑已知 XMLHttpRequest 的响应正文,inject code via a content script 以使用自定义(全功能)构造函数覆盖默认的 XMLHttpRequest 构造函数,该构造函数在触发真实事件之前重写响应。确保您的 XMLHttpRequest 对象完全符合 Chrome 的内置 XMLHttpRequest 对象,否则 AJAX 繁重的网站将会崩溃。

在其他情况下,您可以使用chrome.webRequestchrome.declarativeWebRequest API 将请求重定向到data:-URI。与 XHR 方法不同,您不会获得请求的原始内容。实际上,请求永远不会到达服务器,因为重定向只能在实际请求发送之前完成。如果您重定向 main_frame 请求,用户将看到 data:-URI 而不是请求的 URL。

【讨论】:

  • 我认为 data:-URI 的想法行不通。我只是尝试这样做,似乎 CORS 阻止了它。发出原始请求的页面最后说:“请求被重定向到'data:text/json;,{...}',这对于需要预检的跨域请求是不允许的。”
  • @Joe 无法在 Chromium 39.0.2171.96 中重现
  • @RobW,有哪些技巧或解决方案可以阻止 URL 变为 data:text...
  • @Pacerier 没有真正令人满意的解决方案。在我的回答中,我已经提到了使用内容脚本替换内容的选项,但除此之外,您不能“修改”响应而不导致 URL 更改。
  • 我试过这个解决方案。请注意,除了 XMLHttpRequest 之外,您可能还需要覆盖 fetch()。限制是不拦截浏览器对js/images/css的请求。
【解决方案2】:

我刚刚发布了一个可以做到这一点的 Devtools 扩展 :)

它被称为篡改,它基于mitmproxy,它允许您查看当前选项卡发出的所有请求,修改它们并在下次刷新时提供修改后的版本。

这是一个相当早期的版本,但它应该与 OS X 和 Windows 兼容。让我知道它是否不适合你。

您可以在这里获取它http://dutzi.github.io/tamper/

这是如何工作的

正如@Xan 在下面评论的那样,该扩展通过本机消息传递与扩展mitmproxy 的python 脚本进行通信。

该扩展使用chrome.devtools.network.onRequestFinished 列出所有请求。

当您单击请求时,它会使用请求对象的getContent() 方法下载其响应,然后将该响应发送到将其保存在本地的python 脚本。

然后它在编辑器中打开文件(对于 OSX 使用 call 或对于 Windows 使用 subprocess.Popen)。

python 脚本使用 mitmproxy 侦听通过该代理进行的所有通信,如果它检测到对已保存文件的请求,它会提供已保存的文件。

我使用 Chrome 的代理 API(特别是 chrome.proxy.settings.set())将 PAC 设置为代理设置。该 PAC 文件将所有通信重定向到 python 脚本的代理。

mitmproxy 的一大优点是它还可以修改 HTTPs 通信。所以你也有:)

【讨论】:

  • 顺便说一下,如果你能更好地解释这里使用的技术,那将会有所帮助。
  • 有趣的 Devtools 扩展!但是,似乎只能用 Tamper 修改响应 headers 而不能修改响应 body
  • 安装问题。
  • 我们可以用这个修改响应正文吗?
  • 无法安装:/需要新的解决方案
【解决方案3】:

就像@Rob w 所说,我已经覆盖了XMLHttpRequest,这是修改任何站点中任何XHR 请求的结果(就像透明修改代理一样工作):

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
        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) {}

            console.log('Caught! :)', method, URL/*, _this.responseText*/);
        }
        // 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);
};

例如,Tampermonkey 可以成功地使用此代码在任何网站上进行任何修改:)

【讨论】:

  • 我使用了你的代码,它在控制台上记录了捕获的内容,但它并没有改变我的应用程序得到的响应(Angular)。
  • @AndréRoggeriCampos 我遇到了同样的事情。 Angular 使用较新的 response 而不是 responseText,因此您只需将 Object.defineProperty 更改为使用 response
  • 非常感谢!它适用于我的 chrome 扩展!
  • 这似乎运作良好!如果我需要在我的生产站点中防止这种情况发生,有什么办法吗?
【解决方案4】:

是的。可以使用chrome.debugger API,它授予对Chrome DevTools Protocol 的扩展访问权限,它通过其Network API 支持HTTP 拦截和修改。

这个解决方案是a comment on Chrome Issue 487422建议的:

对于任何想要目前可行的替代方案的人,您可以在背景/事件页面中使用chrome.debugger 附加到您想要收听的特定选项卡(或者如果可能,请附加到所有选项卡) t 亲自测试所有选项卡),然后使用调试协议的网络 API。

唯一的问题是标签的视口顶部会出现通常的黄色条,除非用户在chrome://flags 中将其关闭。

首先,将调试器附加到目标:

chrome.debugger.getTargets((targets) => {
    let target = /* Find the target. */;
    let debuggee = { targetId: target.id };

    chrome.debugger.attach(debuggee, "1.2", () => {
        // TODO
    });
});

接下来,发送Network.setRequestInterceptionEnabled 命令,这将启用网络请求的拦截:

chrome.debugger.getTargets((targets) => {
    let target = /* Find the target. */;
    let debuggee = { targetId: target.id };

    chrome.debugger.attach(debuggee, "1.2", () => {
        chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });
    });
});

Chrome 现在将开始发送 Network.requestIntercepted 事件。为他们添加一个监听器:

chrome.debugger.getTargets((targets) => {
    let target = /* Find the target. */;
    let debuggee = { targetId: target.id };

    chrome.debugger.attach(debuggee, "1.2", () => {
        chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });
    });

    chrome.debugger.onEvent.addListener((source, method, params) => {
        if(source.targetId === target.id && method === "Network.requestIntercepted") {
            // TODO
        }
    });
});

在监听器中,params.request 将是对应的Request 对象。

使用Network.continueInterceptedRequest发送回复:

  • 将所需 HTTP 原始响应(包括 HTTP 状态行、标头等!)的 base64 编码作为 rawResponse 传递。
  • params.interceptionId 传递为interceptionId

请注意,我根本没有测试过这些。

【讨论】:

  • 看起来很有希望,虽然我现在正在尝试(Chrome 60),要么我错过了一些东西,要么仍然不可能; setRequestInterceptionEnabled 方法似乎没有包含在 DevTools 协议 v1.2 中,我找不到将其附加到最新(树尖)版本的方法。
  • 我尝试了这个解决方案,它在一定程度上奏效了。如果你想修改请求,这个解决方案很好。如果要根据服务器返回的响应来修改响应,是没有办法的。那时没有任何回应。因为你可以像作者所说的那样覆盖 rawresponse 字段。
  • chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true }); 失败,“找不到 Network.setRequestInterceptionEnabled”
  • @MultiplyByZer0, Ok 设法让它工作。 i.stack.imgur.com/n0Gff.png 但是,需要删除“顶栏”,即需要设置浏览器标志,然后重新启动浏览器,这意味着需要另一种真正的解决方案。
  • @Pacerier 你说得对,这个解决方案并不理想,但我不知道有什么更好的解决方案。此外,正如您所注意到的,此答案不完整,需要更新。希望我很快就会这样做。
【解决方案5】:

Chrome 不提供任何 API 来修改响应正文。 Chrome WebRequest APIDeclarativeNetRequest API 都无法做到这一点。

使用桌面应用程序 - 修改任何请求类型的响应

Requestly Desktop App 提供了创建Modify HTTP Response Rule 的功能,然后您可以在任何浏览器中使用它。 Here's the demo video。以下是操作步骤

  1. 安装 Requestly Desktop App 并从连接的应用程序启动您的浏览器
  2. 转到 HTTP 规则并创建修改 HTTP 响应规则
  3. 定义您的 URL 模式并定义您的自定义响应

您可以通过 3 种方式定义您的自定义响应

  1. 静态内容 - 您需要的固定响应
  2. 程序覆盖 - 如果您需要覆盖现有服务器响应中的某些内容
  3. 从文件加载 - 在本地文件中定义您的响应并将其映射到此处。

不仅如此,您还可以change the HTTP Status code to 400 or 500使用这种方法。

这是一个屏幕截图 - 使用 JS 代码覆盖现有响应的示例

使用 Requestly Chrome 扩展 - 仅针对 XHR/fetch 请求修改响应

也可以使用Requestly Chrome Extension 来修改仅由 XHR/fetch 触发的 HTTP 请求的响应。 Here's the demo video using Chrome Extension

由于 Chrome 不提供任何 API,Requestly 会覆盖 XHR 并获取原型对象以挂钩自定义实现,您将获得您在 Requestly 响应修改规则中定义的响应。您可以在the docs 阅读更多相关信息。

PS:我请求构建

【讨论】:

    【解决方案6】:

    虽然 Safari 内置了此功能,但到目前为止我为 Chrome 找到的最佳解决方法是使用赛普拉斯的 intercept 功能。它干净利落地允许我在 Chrome 中存根 HTTP 响应。我打电话给cy.intercept 然后cy.visit(<URL>) 它拦截并为访问页面发出的特定请求提供存根响应。这是一个例子:

    cy.intercept('GET', '/myapiendpoint', {
      statusCode: 200,
      body: {
        myexamplefield: 'Example value',
      },
    })
    cy.visit('http://localhost:8080/mytestpage')
    

    注意:您可能还需要configure Cypress 来禁用某些特定于 Chrome 的安全设置。

    【讨论】:

    • 切换到 Safari 来解决我的问题真的帮了我很大的忙,谢谢!
    猜你喜欢
    • 1970-01-01
    • 2019-03-11
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 2014-01-18
    • 1970-01-01
    • 2016-01-02
    • 2021-10-07
    相关资源
    最近更新 更多