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

dphi5xsq  于 2023-08-02  发布在  Java
关注(0)|答案(6)|浏览(186)

我想拦截JavaScript中的fetch 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实现相同的功能。我该怎么办?

5n0oy7gb

5n0oy7gb1#

现有的答案显示了在浏览器中模拟fetch的一般结构,但忽略了重要的细节。
accepted answer展示了用自定义实现替换window.fetch函数的一般模式,该自定义实现拦截调用并将参数转发给fetch。然而,所示的模式不允许拦截函数对响应执行任何操作(例如,读取状态或主体或注入模拟),因此仅对记录请求参数有用。这是一个非常狭窄的用例。
This answer使用async函数让fetch promise上的拦截器await处理响应(mocking,阅读等),但(在写入时)有一个多余的闭包,并且没有显示如何非破坏性地读取响应体。它还包含一个导致堆栈溢出的变量别名错误。
This answer是迄今为止最完整的,但在回调中有一些不相关的噪音,并且没有提到任何关于克隆响应以使拦截器能够收集主体的内容。它没有说明如何返回模拟。
这里有一个最小的、完整的例子来纠正这些问题,展示了如何处理参数日志记录,在不损害原始调用者by cloning the response的情况下阅读主体,以及(可选地)提供模拟响应。

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

字符串

bis0qfac

bis0qfac2#

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

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

字符串

ct2axkht

ct2axkht3#

为了拦截响应体,你需要创建一个新的Promise,并将当前的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(error);
      })
  });
}

字符串

6yjfywim

6yjfywim4#

const fetch = window.fetch;
window.fetch = (...args) => (async(args) => {
    var result = await fetch(...args);
    console.log(result); // intercept response here
    return result;
})(args);

字符串

abithluo

abithluo5#

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

字符串

qojgxg4l

qojgxg4l6#

您可以使用return-fetch库拦截请求或响应。https://github.com/deer-develop/return-fetch

import returnFetch from 'return-fetch';

const requestUrls: string[] = [];
const responseBodies: string[] = [];

// save global fetch reference
const globalFetch = window.fetch;

// declare your own fetch
const myFetch = returnFetch({
  fetch: globalFetch, // input global fetch here.
  interceptors: {
    request: async (args) => {
      requestUrls.push(args[0]?.toString());
      return args;
    },
    response: async (response) => {
      const cloned = response.clone();
      const body = await cloned.text();
      responseBodies.push(body);

      return response;
    },
  },
});

// replce global fetch with your own fetch.
window.fetch = myFetch;

fetch('https://jsonplaceholder.typicode.com/todos/1').then(() => {
  console.log('requestUrls', requestUrls);
  console.log('repsonseBodies', responseBodies);
});

字符串
以下是详细的文档:https://return-fetch.myeongjae.kim

相关问题