在 JavaScript 中拦截 fetch() API 请求和响应

新手上路,请多包涵

我想拦截 JavaScript 中的获取 API 请求和响应。

例如,在发送请求之前我想拦截请求 URL。我也想在响应到达后拦截它。

以下代码用于拦截所有 XMLHTTPRequest 的响应。

 (function(open) {
  XMLHttpRequest.prototype.open = function(XMLHttpRequest) {
    var self = this;
    this.addEventListener("readystatechange", function() {
      if (this.responseText.length > 0 &&
          this.readyState == 4 &&
          this.responseURL.indexOf('www.google.com') >= 0) {

        Object.defineProperty(self, 'response', {
          get: function() { return bValue; },
          set: function(newValue) { bValue = newValue; },
          enumerable: true,
          configurable: true
        });
        self.response = 'updated value' // Intercepted Value
      }
    }, false);
    open.apply(this, arguments);
  };
})(XMLHttpRequest.prototype.open);

我想为 fetch() API 实现相同的功能。我怎样才能做到这一点?

原文由 Hariharan Subramanian 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

为了拦截获取请求和参数,我们可以采用下面提到的方式。它解决了我的问题。

  const constantMock = window.fetch;
 window.fetch = function() {
     // Get the parameter in arguments
     // Intercept the parameter here
    return constantMock.apply(this, arguments)
 }

原文由 Hariharan Subramanian 发布,翻译遵循 CC BY-SA 4.0 许可协议

现有答案显示浏览器中模拟的一般结构 fetch 但省略了重要细节。

接受的答案 显示了用自定义实现替换 window.fetch 函数的一般模式,该实现拦截调用并将参数转发给 fetch 。但是,显示的模式不允许拦截函数对响应做任何事情(例如,读取状态或正文或注入模拟),因此仅对记录请求参数有用。这是一个非常狭窄的用例。

这个答案 使用 async 函数让拦截器 awaitfetch 承诺并可能使用响应(等模拟,阅读)写作时间)有一个多余的闭包,并且没有展示如何非破坏性地读取响应主体。它还包含一个导致堆栈溢出的变量别名错误。

这个答案 是迄今为止最完整的,但在回调中有一些不相关的噪音,并且没有提到任何关于克隆响应以使拦截器能够收集主体的内容。它没有说明如何返回模拟。

这是一个纠正这些问题的最小的完整示例,展示了如何处理参数日志记录, 通过克隆响应 和(可选)提供模拟响应来读取正文而不损害原始调用者。

 const {fetch: origFetch} = window;
window.fetch = async (...args) => {
  console.log("fetch called with args:", args);
  const response = await origFetch(...args);

  /* work with the cloned response in a separate promise
     chain -- could use the same chain with `await`. */
  response
    .clone()
    .json()
    .then(body => console.log("intercepted response:", body))
    .catch(err => console.error(err))
  ;

  /* the original response can be resolved unmodified: */
  //return response;

  /* or mock the response: */
  return {
    ok: true,
    status: 200,
    json: async () => ({
      userId: 1,
      id: 1,
      title: "Mocked!!",
      completed: false
    })
  };
};

// test it out with a typical fetch call
fetch("https://jsonplaceholder.typicode.com/todos/1")
  .then(response => response.json())
  .then(json => console.log("original caller received:", json))
  .catch(err => console.error(err))
;

原文由 ggorlen 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题