从零实现axios(3.1小节-实现拦截器1)

34 阅读3分钟

实现拦截器1

拦截器的作用就是拦截请求或响应。我们在请求发出去前进行拦截,就可以对请求进行统一的处理,比如往请求头添加字段等;我们也可在响应返回之前对后端数据进行统一的处理。 我们可以通过以下方式来添加一个拦截器

// 添加请求拦截器
axios.interceptors.request.use(
  function (config) {
    // 在发送请求之前做些什么
    return config;
  },
  function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);

// 添加响应拦截器
axios.interceptors.response.use(
  function (response) {
    // 对响应数据做点什么
    return response;
  },
  function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);

根据以上代码,我们可以知道axios是通过 axios.interceptors 来添加拦截器,因此我们在 Axios 类中实现拦截器的功能,首先我们在Axios构造函数中通 new InterceptorManager() 分别实例化请求和响应的拦截管理对象,该管理对象的作用是负责添加、删除、处理拦截器。

/**
 * axios实例构造函数
 *
 * @param {Object} instanceConfig 实例配置对象
 */
function Axios(instanceConfig) {
  this.defaults = instanceConfig;
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager(),
  };
}

上面例子中添加的请求拦截器和响应拦截器会在 request 请求中被使用。request函数通过 this.interceptors.request.forEach 把添加的请求拦截器依次插入到 chain 数组的 dispatchRequest 方法前面,这样子就可以在请求发出去前先进行处理,同理通过 this.interceptors.response.forEach 把添加的响应拦截器依次插入到 chain 数组的 dispatchRequest 方法后面,就可在响应返回前进行拦截处理。

Axios.prototype.request = function request(config) {
  // 以上部分代码请参考前面的章节或最后一章提供的参考资料

  var chain = [dispatchRequest, undefined];
  var promise = Promise.resolve(config);

  // 把请求拦截器添加到requestInterceptorChain数组中
  var requestInterceptorChain = [];
  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
  });


  // 把响应拦截器添加到responseInterceptorChain数组中
  var responseInterceptorChain = [];
  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
  });

  // 把请求拦截处理函数添加到chain数组前面去,在dispatchRequest请求发出前进行拦截处理
  Array.prototype.unshift.apply(chain, requestInterceptorChain);
  // 把响应拦截处理函数添加到chain数组前面去,在响应返回前进行拦截处理
  chain = chain.concat(responseInterceptorChain);

  while (chain.length) {
    promise = promise.then(chain.shift(), chain.shift());
  }
  // 添加拦截器后相当于 Promise.resolve(config)
  //                  .then(reqFulfilled, reqRejected) // 请求拦截处理函数
  //                  .then(dispatchRequest, undefined)
  //                  .then(resFulfilled, resRejected) // 响应拦截处理函数
  return promise;
};

接下来,我们在 core 文件夹下创建 InterceptorManager.js文件,在文件里我们实现 InterceptorManager 拦截管理类。该类提供三个方法,其中 use 方法就是用来添加拦截器,并返回一个 id,该 id 可用于删除当前拦截器。第二个方法是 eject 方法,该方法传入 use 方法返回的 id 就可以删除对应的拦截器。第三个方法是 forEach,该方法传入一个回调函数,在该函数中依次处理拦截器

"use strict";

var utils = require("../utils");

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

/**
 * 添加新的拦截器到栈
 *
 * 这两个参数最终会被promise.then使用, promise.then(fulfilled, rejected)
 * 
 * @param {Function} fulfilled promise.then的处理函数, 即上面例子中请求发送前的处理函数
 * @param {Function} rejected promise.reject的处理函数, 即上面例子中请求失败的处理函数
 *
 * @return {Number} 被用来移除拦截器的id
 */
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
  this.handlers.push({
    fulfilled: fulfilled,
    rejected: rejected,
  });
  return this.handlers.length - 1;
};

/**
 * 从栈中移除一个拦截器
 *
 * @param {Number} id The ID that was returned by `use`
 */
InterceptorManager.prototype.eject = function eject(id) {
  if (this.handlers[id]) {
    this.handlers[id] = null;
  }
};

/**
 * 迭代所有被注册的拦截器
 *
 * 该方法可以忽略值为null的拦截器
 *
 * @param {Function} fn 处理拦截器对象的函数
 */
InterceptorManager.prototype.forEach = function forEach(fn) {
  // 迭代处理所有的拦截器
  utils.forEach(this.handlers, function forEachHandler(h) {
    if (h !== null) {
      // fn函数为unshiftRequestInterceptors、pushResponseInterceptors函数,参数为interceptor拦截器对象
      // h参数为handlers中保存的interceptor拦截器对象,包含fulfilled, rejected两个拦截处理方法
      fn(h);
    }
  });
};

module.exports = InterceptorManager;