挂钩所有Fetch Api AJAX请求

col*_*ick 8 javascript ajax fetch-api

你如何挂钩所有使用Fetch Api的AJAX请求?以前我们可以做这样的事情来挂钩所有的XMLHttpRequest:

(function() {
    var origOpen = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function() {
      console.log('request started!');
      this.addEventListener('load', function() {
          console.log('request completed!');
          console.log(this.readyState); //will always be 4 (ajax is completed successfully)
          console.log(this.responseText); //whatever the response was
      });
      origOpen.apply(this, arguments);
    };
  })();
Run Code Online (Sandbox Code Playgroud)

或者更好的是,如果你想添加上面的函数,你将如何挂钩所有Fetch Api和所有XMLHttpRequest AJAX请求?

小智 5

由于承诺的性质,这很容易做到:

var taperFunction = response => response;
var originalFetch = fetch;
fetch = (input, init) => originalFetch(input, init)
    .then(response => new Promise((resolve) => {
        resolve(taperFunction(response));
    }));
Run Code Online (Sandbox Code Playgroud)

还有一个更复杂(明确)的例子:

var originalFetch = fetch;
fetch = (input, init) => {
    debugger; // do what ever you want with request or reject it immediately
    return originalFetch(input, init).then(response => {
        // it is not important to create new Promise in ctor, we can await existing one, then wrap result into new one
        return new Promise((resolve) => {
            response.clone() // we can invoke `json()` only once, but clone do the trick
                .json()
                .then(json => {
                    debugger; // do what ever you want with response, even `resolve(new Response(body, options));`
                    resolve(response);
                });
        });
    });
};

Run Code Online (Sandbox Code Playgroud)


小智 1

事实上,Fetch Api 是原生浏览器支持的,只有一个接口:fetch。\n构造函数返回一个Promise ,当你想返回你的 Promise 重写 fetch 时,你无法得到Request\xe3\x80\x81 \Response的构造函数。

\n\n

下面的代码不能很好地工作。

\n\n
(function() {\n    var oldFectch = fetch;\n    fetch.consotructor = function() {\n        return new Promise(resolve, reject) {\n            // your hook code\n        };\n    };\n})();\n
Run Code Online (Sandbox Code Playgroud)\n\n

那么,这是否意味着我们无法 hook 所有 Fetch Api ?不!

\n\n

首先,感谢window.fetch polyfill

\n\n

然后,让我们做一些事情(编辑fetch.js)并摇滚。

\n\n
(function(self) {\n    \'use strict\';\n\n    // comment or delete the following code block\n    // if (self.fetch) {\n    //    return\n    // }\n\n    var support = {\n        searchParams: \'URLSearchParams\' in self,\n        iterable: \'Symbol\' in self && \'iterator\' in Symbol,\n        // ...\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后,把每件事都做得更好!

\n\n
self.fetch = function(input, init) {\n  return new Promise(function(resolve, reject) {\n    var request = new Request(input, init)\n    var xhr = new XMLHttpRequest()\n\n    // Here we go!\n    // Now we get the XMLHttpRequest Object\n    // Do what you want!\n\n    xhr.onload = function() {\n      var options = {\n        status: xhr.status,\n        statusText: xhr.statusText,\n        headers: parseHeaders(xhr.getAllResponseHeaders() || \'\')\n      }\n      options.url = \'responseURL\' in xhr ? xhr.responseURL : options.headers.get(\'X-Request-URL\')\n      var body = \'response\' in xhr ? xhr.response : xhr.responseText\n      resolve(new Response(body, options))\n    }\n    // ...\n
Run Code Online (Sandbox Code Playgroud)\n