【问题标题】:Hook all Fetch Api AJAX requests挂钩所有 Fetch Api AJAX 请求
【发布时间】:2017-11-27 11:08:15
【问题描述】:

如何挂钩所有使用 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);
    };
  })();

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

【问题讨论】:

  • 这个运气好吗?规范中似乎没有任何内容。

标签: javascript ajax fetch-api


【解决方案1】:

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

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

还有一个更复杂(显式)的例子:

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

【讨论】:

    【解决方案2】:

    其实FetchApi是原生浏览器支持的,只有一个接口:fetch。 构造函数返回一个Promise,当你想返回你的Promise重写fetch的构造函数时,你无法得到RequestResponse

    下面的代码不好用。

    (function() {
        var oldFectch = fetch;
        fetch.consotructor = function() {
            return new Promise(resolve, reject) {
                // your hook code
            };
        };
    })();
    

    那么,这是否意味着我们不能挂钩所有 Fetch Api ? 不!

    首先,感谢window.fetch polyfill

    那么,让我们做点什么(编辑fetch.js)然后摇滚吧。

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

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

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

    【讨论】:

      【解决方案3】:

      使用asyncawait,很简单:

      const oldFetch = window.fetch
      window.fetch = async (input, options) => {
          return await oldFetch(input, options)
      }
      

      一个例子:

      const oldFetch = window.fetch
      window.fetch = async (input, options) => {
          // modify the request here
          console.log(input)
      
          let response = await oldFetch(input, options)
      
          // modify the response
          let content = await response.text()
          content = 'goodbye!'
          return new Response(content, {
              status: response.status,
              statusText: response.statusText,
              headers: response.headers
          })
      }
      
      console.log(await (await fetch('/hello')).text())
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-31
        • 2019-12-11
        • 1970-01-01
        • 1970-01-01
        • 2011-07-09
        • 2017-11-09
        • 1970-01-01
        相关资源
        最近更新 更多