在Javascript

时间:2017-07-31 20:58:06

标签: javascript ajax xmlhttprequest interceptor fetch-api

我想拦截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实现相同的功能。

先谢谢..

5 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:4)

要拦截响应主体,您需要创建一个新的Promisse,并将电流解析或拒绝为“ then”代码。它为我解决了,并保留了真正的应用程序的内容。例如。反应等等。

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

答案 2 :(得分:3)

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

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

This answer使用async函数使拦截器await兑现fetch的诺言,并可能与响应(模拟,阅读等)一起工作,但(在撰写本文时)具有多余的结束语,并且没有显示如何非破坏性地读取响应主体。它还包含一个变量别名错误,导致堆栈溢出。

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:", 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))
;

答案 3 :(得分:1)

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

答案 4 :(得分:0)

进一步了解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;
            })
    }
})();