实现一下axios的拦截器

248 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第31天,点击查看活动详情

axios是基于Promise的HTTP请求库,封装了XHR简化了我们对xhr的使用,其中axios中的拦截器可以说是其一大亮点了。

使用

//引入
    import axios from "axios";
 // 设置请求拦截器  config 配置对象
    axios.interceptors.request.use(function one(config) {
      console.log('请求拦截器成功 1');
      return config;
    }, function (error) {
      console.log('请求拦截器失败 1');
      return Promise.reject(error);
    });

    axios.interceptors.request.use(function two(config) {
      console.log('请求拦截器成功 2');
      return config;
    }, function (error) {
      console.log('请求拦截器失败 2');
      return Promise.reject(error);
    });

    // 设置响应拦截器
    axios.interceptors.response.use(function (response) {
      console.log('响应拦截器成功 1');
      return response;
    }, function (error) {
      console.log('响应拦截器失败 1');
      return Promise.reject(error);
    });

    axios.interceptors.response.use(function (response) {
      console.log('响应拦截器成功 2');
      return response;
    }, function (error) {
      console.log('响应拦截器失败 2');
      return Promise.reject(error);
    });

    // 发送请求
    axios({
      method: 'GET',
      url: 'http://localhost:3000/posts'
    }).then(response => {
      console.log(response);
    });

上面的代码就是对拦截器的基本使用,拦截器分为请求前拦截,请求拦截器可以在发出请求之前,按照拦截器添加顺序执行,再发送请求。而响应拦截器则是在收到响应之后,按照拦截器添加顺序执行后,再返回响应结果。主要作用如下:

  • 数据转换
  • 添加额外的数据,例如往header添加信息等
  • 日志记录,输出请求响应时间和失败率等

实现

我们简单的实现一下整个过程,由于只是实现拦截器所以XHR的东西我们就直接省略不写了。

首先是我们的构造函数,接受我们传入的参数,同时有一个实例属性interceptions里面有两个属性,分别是我们的请求前拦截和响应后拦截,各是一个拦截器管理器实例对象

function Axios (config) {
      this.axios = config;
      this.interceptors = {
        request: new InterceptorManager(),
        response: new InterceptorManager(),
      }
}

拦截器管理器构造函数有个属性是处理对象集,

    // 拦截器管理器构造函数
    function InterceptorManager () {
      this.handlers = [];
    }

同时拥有一个use实例方法来将拦截后的成功处理和失败处理方式压入处理对象集中。

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

首先遍历请求拦截器按照顺序将处理函数添加到数组前部,然后遍历响应拦截器按照顺序将处理函数添加到数组末尾

// 发送请求
Axios.prototype.request = function (config) {
      // 创建一个 promise 对象
      let promise = Promise.resolve(config);
      // 创建一个数组
      const chains = [dispatchRequest, undefined];
      // 处理拦截器
      // 请求拦截器 将请求拦截器的回调 压入到 chains 的前面  request.handles = []
      this.interceptors.request.handlers.forEach(item => {
        chains.unshift(item.fulfilled, item.rejected);
      });
      // 响应拦截器
      //响应拦截器,将响应拦截器的回调压入chains的后面 request.handles=[]
      this.interceptors.response.handlers.forEach(item => {
        chains.push(item.fulfilled, item.rejected);
      });
      // 遍历
      while (chains.length > 0) {
        promise = promise.then(chains.shift(), chains.shift());
      }

      return promise;
}
// 发送请求
    function dispatchRequest (config) {
      // 返回一个 promise 队列
      return new Promise((resolve, reject) => {
        resolve({
          status: 200,
          statusText: 'OK'
        });
      });
    }

测试

    // 创建实例
    let context = new Axios({});
    // 创建 axios 函数
    let axios = Axios.prototype.request.bind(context);
    //将 context 属性 config interceptors 添加至 axios 函数对象身上
    Object.keys(context).forEach(key => {
      axios[key] = context[key];
    });
    // 设置请求拦截器  config 配置对象
    axios.interceptors.request.use(function one(config) {
      console.log('请求拦截器成功 1');
      return config;
    }, function (error) {
      console.log('请求拦截器失败 1');
      return Promise.reject(error);
    });

    axios.interceptors.request.use(function two(config) {
      console.log('请求拦截器成功 2');
      return config;
    }, function (error) {
      console.log('请求拦截器失败 2');
      return Promise.reject(error);
    });

    // 设置响应拦截器
    axios.interceptors.response.use(function (response) {
      console.log('响应拦截器成功 1');
      return response;
    }, function (error) {
      console.log('响应拦截器失败 1');
      return Promise.reject(error);
    });

    axios.interceptors.response.use(function (response) {
      console.log('响应拦截器成功 2');
      return response;
    }, function (error) {
      console.log('响应拦截器失败 2');
      return Promise.reject(error);
    });

    // 发送请求
    axios({
      method: 'GET',
      url: 'http://localhost:3000/posts'
    }).then(response => {
      console.log(response);
    });