繁体   English   中英

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

[英]Intercept fetch() API requests and responses in JavaScript

我想拦截 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 实现相同的功能。 我怎样才能做到这一点?

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

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

这个答案使用async函数让拦截器await fetch promise 并大概处理响应(模拟,读取等)但是(在撰写本文时)有一个多余的关闭并且没有显示如何读取响应体无损。 它还包含一个导致堆栈溢出的变量别名错误。

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

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

 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)) ;

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

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

为了拦截响应主体,您需要创建一个新的 Promise 并将当前解析或拒绝为“then”代码。 它为我解决了问题,并保留了真实应用程序的内容,例如 React 等。

const constantMock = window.fetch;
window.fetch = function() {
  console.log(arguments);

  return new Promise((resolve, reject) => {
    constantMock
      .apply(this, arguments)
      .then((response) => {
        if (response.url.indexOf("/me") > -1 &&
            response.type != "cors") {
          console.log(response);
          // do something for specificconditions
        }
        resolve(response);
      })
      .catch((error) => {
        reject(response);
      })
  });
}
const fetch = window.fetch;
window.fetch = (...args) => (async(args) => {
    var result = await fetch(...args);
    console.log(result); // intercept response here
    return result;
})(args);

继 Hariharan 的回答之后,以下是我在每次获取请求之前和之后如何在 Redux 中更新微调器状态

import store from './../store';

// Set up interceptor on all fetch API calls
// Increments redux spinner state when api is called
// Decrements redux spinner state again when it is returned
(function() {
    const originalFetch = window.fetch;
    window.fetch = function() {
        store.dispatch({type: 'show-spinner'})
        return originalFetch.apply(this, arguments)
            .then((res) => {
                store.dispatch({type: 'hide-spinner'})
                return res;
            })
    }
})();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM