axios-2-request-拦截器

89 阅读2分钟

书接上回,上次说到 mergeConfig,这次是 this.request

request

axios.get("xx",params: { ID: 12345 })

/**
   * Dispatch a request
   *
   * @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults)
   * @param {?Object} config
 */
   
Axios.prototype.request = function request(configOrUrl, config){
     if (typeof configOrUrl === 'string') {
      config = config || {};
      config.url = configOrUrl;
    } else {
      config = configOrUrl || {};
    }
    // 合并配置项
   config = mergeConfig(this.defaults, config);
   
   // 由于 Axios 的 内部方法 中 使用 了 
   // this.interceptors = {
   //  request: new InterceptorManager_1(),
   // }
   // this.interceptors.request 是 拦截器 的实例,可以使用原型的方法,这种写法可以做到更好的分离
   // 重点 是拦截器
    var requestInterceptorChain = [];
     this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor){
         requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
     })
     
     var responseInterceptorChain = [];
     
      this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
      responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
    });
    
    
    // 出现了一个 chain,其中的 dispatchRequest 是核心方法
     var promise
     var chain = [dispatchRequest, undefined];
    //把 requestInterceptorChain unshift
    // 由于 chain 是个数组,直接 unshift 有问题,利用 apply方法
      Array.prototype.unshift.apply(chain, requestInterceptorChain);
      
      chain = chain.concat(responseInterceptorChain);
        
      // 这里的config 很重要,是作为promise 的实参,
      promise = Promise.resolve(config);
      
      //requestInterceptorChain 是 一个对象数组,
      // 对象的第一项是 fullfilled函数,第二项是 rejected函数
      // {fullfilled:function(config){return config },reject:fn}
      //他们的这些函数config的就是从这里来的,修改了config
      // 一定要return,以便后续能够拿到
      
      while (chain.length) {
        promise = promise.then(chain.shift(), chain.shift());
      }

      return promise;
    
    //
}

拦截器解析

// 当用户 不断的 `use` 添加 拦截器的时候
// 比如是用请求拦截器, 请求拦截器 实例会一直 push,最终形成
this.handler = [
 { 
    fullfilled:function(config){return config },
    rejected:fn 
 },{
    fullfilled:fn,
    rejected:undefined
  } 
]
当使用 `this.interceptors.request.forEach` 的时候
unshiftRequestInterceptors 中的形参(interceptor) = 
({ 
  fullfilled:function(config){ return config },
  rejected:fn 
})

requestInterceptorChain.unshift({ fullfilled:function(config){return config },rejected:fn })


this.defaults

var defaults = {
    transitional: transitional,
    adapter: getDefaultAdapter(),
    timeout: 0,
     validateStatus: function validateStatus(status) {
      return status >= 200 && status < 300;
    },
    ....
}

var defaults_1 = defaults;

 function Axios(instanceConfig) {
    
    this.defaults = instanceConfig;

    this.interceptors = {
      request: new InterceptorManager_1(),
      response: new InterceptorManager_1()
    };
  }

拦截器

// 添加请求拦截器 
axios.interceptors.request.use(function (config) { 
    return config;
 }, function (error) { 
    return Promise.reject(error); 
});

// 添加响应拦截器 
axios.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。 
   return response; 
}, function (error) { 
// 超出 2xx 范围的状态码都会触发该函数。 
    return Promise.reject(error); 
});

function InterceptorManager() {
    this.handlers = [];
  }
// 不断的 push 
 InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {
    this.handlers.push({
      fulfilled: fulfilled,
      rejected: rejected,
      synchronous: options ? options.synchronous : false,
      runWhen: options ? options.runWhen : null
    });
    return this.handlers.length - 1;
  };
  
 InterceptorManager.prototype.forEach = function forEach(fn) {
    utils.forEach(this.handlers, function forEachHandler(h) {
      if (h !== null) {
        fn(h);
      }
    });
  };
  
 
  
   InterceptorManager.prototype.clear = function clear() {
    if (this.handlers) {
      this.handlers = [];
    }
  };
  
  InterceptorManager.prototype.eject = function eject(id) {
    if (this.handlers[id]) {
      this.handlers[id] = null;
    }
  };

拦截器核心代码简化版


    function InterceptorManager() {
      this.handlers = [];
    }

    InterceptorManager.prototype.use = function use(fulfilled, rejected) {
      this.handlers.push({
        fulfilled: fulfilled,
        rejected: rejected,
      });
    };

    InterceptorManager.prototype.forEach = function forEach(fn) {
      this.handlers.forEach(h => {
        if (h !== null) {
          fn(h);
        }
      })
    };




    function Bxios() {
      this.defaultConfig = {
        name: 'zs',
        age: 20
      }
      this.interceptors = {
        request: new InterceptorManager(),
        response: new InterceptorManager()
      };
    }

    function mid(res) {
      
      return Promise.resolve({res,mid:"mid"})
    }


    Bxios.prototype.request = function (config) {

      config = Object.assign(this.defaultConfig, config);

      var before = [];


      this.interceptors.request.forEach(function (interceptor) {
        before.unshift(interceptor.fulfilled, interceptor.rejected);
      })

      var after = [];

      this.interceptors.response.forEach(function (interceptor) {
        after.push(interceptor.fulfilled, interceptor.rejected);
      })



      var chain = [mid, undefined];

      Array.prototype.unshift.apply(chain, before);

      chain = chain.concat(after);

      promise = Promise.resolve(config);

      while (chain.length) {
        promise = promise.then(chain.shift(), chain.shift());
      }

      return promise;

    }


    var a = new Bxios

    a.interceptors.request.use(function (config) {
      return {
        ...config,
        xx: 'before'
      }
    })

    a.interceptors.response.use(function (config) {
      return {
        ...config,
        after: 'after'
      }
    })

    a.request().then(res=>{
      console.log(res,"fininal")
    })

 Promise.resolve(1)
     .then(res=>{return res+1})
     .then(res=>{
      console.log(res)
  })

从拦截器的例子中可以看到对于数组的Array.prototype.unshift.apply(chain, requestInterceptorChain); 还是挺方便的,对于 this.request = { request: new InterceptorManager(), response: new InterceptorManager() }中的原型链的使用也需要学习,还有 promise的链式调用保证顺序也挺有意思

今天的拦截器就先写到这里 2022/9/29, 下一次写 dispatchRequest方法,还有一天国庆