简体   繁体   English

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

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

I want to intercept fetch API requests and responses in JavaScript.我想拦截 JavaScript 中的获取 API 请求和响应。

For example, before sending the request I want to intercept the request URL.例如,在发送请求之前我想拦截请求 URL。 I'd like to intercept the response once it arrives as well.我也想在响应到达后拦截它。

The below code is for intercepting responses of all XMLHTTPRequest s.下面的代码用于拦截所有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);

I want to implement the same feature for fetch() API.我想为fetch() API 实现相同的功能。 How can I do this?我怎样才能做到这一点?

Existing answers show the general structure for mocking fetch in the browser but omit important details.现有答案显示了在浏览器中模拟fetch的一般结构,但省略了重要细节。

The accepted answer shows the general pattern for replacing the window.fetch function with custom implementation that intercepts the call and forwards the arguments to fetch .接受的答案显示了用自定义实现替换window.fetch函数的一般模式,该实现拦截调用并将参数转发给fetch However, the pattern shown doesn't let the interception function do anything with the response (for example, read the status or body or inject a mock) so is only useful for logging request parameters.但是,显示的模式不允许拦截函数对响应做任何事情(例如,读取状态或正文或注入模拟),因此仅对记录请求参数有用。 This is a pretty narrow use case.这是一个非常狭窄的用例。

This answer uses an async function to let the interceptor await on the fetch promise and presumably work with the response (mocking, reading, etc) but (at the time of writing) has a superfluous closure and doesn't show how to read the response body non-destructively.这个答案使用async函数让拦截器await fetch promise 并大概处理响应(模拟,读取等)但是(在撰写本文时)有一个多余的关闭并且没有显示如何读取响应体无损。 It also contains a variable aliasing bug leading to a stack overflow.它还包含一个导致堆栈溢出的变量别名错误。

This answer is the most complete so far but has some irrelevant noise in the callback and doesn't mention anything about cloning the response to enable the body to be collected by the interceptor.这个答案是迄今为止最完整的,但在回调中有一些不相关的噪音,并且没有提到任何关于克隆响应以使拦截器能够收集主体的内容。 It doesn't illustrate how a mock could be returned.它没有说明如何返回模拟。

Here's a minimal, complete example that rectifies these issues, showing how to handle parameter logging, reading the body without harming the original caller by cloning the response and (optionally) providing a mock 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)) ;

For intercepting the fetch request and parameter we can go for below mentioned way.为了拦截获取请求和参数,我们可以采用下面提到的方式。 its resolved my issue.它解决了我的问题。

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

For intercepting the response body you need to create a new Promise and resolve or reject current into "then" code.为了拦截响应主体,您需要创建一个新的 Promise 并将当前解析或拒绝为“then”代码。 It solved for me and keep content for real app, eg React, etc.它为我解决了问题,并保留了真实应用程序的内容,例如 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);

Further to Hariharan's answer, Here is how I updated spinner state in Redux before and after each fetch request继 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