Перехватывать ответы и запросы API Fetch() в Javascript

Я хочу перехватить запрос API-интерфейса и получить ответ в Javascript.

Например: перед отправкой запроса необходимо перехватить URL-адрес запроса и после получения ответа хочет перехватить ответ.

Приведенный ниже код предназначен для перехвата ответа All 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.

Заранее спасибо..

2 ответа

Решение

Для перехвата запроса на выборку и параметра мы можем пойти по нижеуказанному пути. это решило мою проблему.

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

Существующие ответы показывают общую структуру издевательства. fetch в браузере, но опустите важные детали.

Принятый ответ показывает общий шаблон для замены window.fetch функция с пользовательской реализацией, которая перехватывает вызов и перенаправляет аргументы в fetch. Однако показанный шаблон не позволяет функции перехвата ничего делать с ответом (например, читать статус или тело или вводить имитацию), поэтому он полезен только для регистрации параметров запроса. Это довольно узкий вариант использования.

В этом ответе используется async функция, позволяющая перехватчику await на fetchобещать и предположительно работать с ответом (насмешка, чтение и т. д.), но (на момент написания) имеет лишнее закрытие и не показывает, как читать тело ответа неразрушающим образом. Он также содержит ошибку псевдонима переменных, приводящую к переполнению стека.

Этот ответ на данный момент является наиболее полным, но он содержит некоторый несущественный шум в обратном вызове и ничего не упоминает о клонировании ответа, чтобы позволить перехватчику собрать тело. Это не иллюстрирует, как можно вернуть макет.

Вот минимальный, полный пример, который устраняет эти проблемы, показывая, как обрабатывать регистрацию параметров, читать тело, не нанося вреда исходному вызывающему, путем клонирования ответа и (необязательно) предоставления фиктивного ответа.

         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:", body))
    .catch(err => console.error(err))
  ;
    
  /* the original response can be resolved unmodified: */
  //return response;
  
  /* or mock the response: */
  return {
    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:", json))
  .catch(err => console.error(err))
;

Для перехвата тела ответа вам нужно создать новый Promisse и разрешить или отклонить текущий в "затем" код. Это решено для меня и сохранить контент для реального приложения. например. реагировать и т.д..

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

В дополнение к ответу Харихарана, вот как я обновил состояние счетчика в 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;
            })
    }
})();
Другие вопросы по тегам