首页前端开发VUEaxios拦截器工作方式及原理源码解析

axios拦截器工作方式及原理源码解析

时间2024-02-11 04:30:02发布访客分类VUE浏览232
导读:收集整理的这篇文章主要介绍了axios拦截器工作方式及原理源码解析,觉得挺不错的,现在分享给大家,也给大家做个参考。 目录axios 拦截器的配置方式use( 方法的定义拦截器如何执行...
收集整理的这篇文章主要介绍了axios拦截器工作方式及原理源码解析,觉得挺不错的,现在分享给大家,也给大家做个参考。
目录
  • axios 拦截器的配置方式
  • use() 方法的定义
  • 拦截器如何执行
    • 拦截器回调方法的添加顺序
    • 同步执行请求拦截器(顺序执行)
    • 异步执行请求拦截器(同时执行)
  • Q& A
    • 拦截器是如何工作的
    • 拦截器的执行顺序
    • 同步& 异步

axios 拦截器的配置方式

本文所用 axios 版本号为:1.3.2

axios 中有两种拦截器:

  • axios.interceptors.request.use(onFulfilled, onRejected, options):配置请求拦截器。
    • onFulfilled 方法在发送请求前执行,接收 config 对象,返回一个新的 config 对象,可在此方法内修改 config 对象。
    • onRejected 方法在 onFulfilled 执行错误后执行,接收 onFulfilled 执行后的错误对象。
    • options 配置参数
      • synchronous:控制请求拦截器是否为异步执行,默认为 true,每个拦截器都可以单独设置,只要有一个设置为 false 则为同步执行,否则为异步执行。
      • runWhen:一个方法,接收 config 对象作为参数,在每次调用设定的拦截器方法前调用,返回结果为 true 时执行拦截器方法。
  • axios.interceptors.response.use(onFulfilled, onRejected, options):配置响应拦截器。
    • onFulfilled 方法在返回响应结果前调用,接收响应对象,返回一个新的响应对象,可在此方法内修改响应对象。
    • onRejected 与 options 同 axios.interceptors.request.use
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.interceptors.request.use(  function (config) {
        throw new Error("999");
        return config;
  }
,  function (error) {
        console.LOG(1, error);
        return Promise.reject(error);
  }
    );
axios.interceptors.request.use(  function (config) {
        throw new Error("888");
        return config;
  }
,  function (error) {
        console.log(2, error);
        return Promise.reject(error);
  }
    );
axios.interceptors.response.use(  function (response) {
        return response;
  }
,  function (error) {
        console.log(3, error);
        return Promise.reject(error);
  }
    );
axios.interceptors.response.use(  function (response) {
        return response;
  }
,  function (error) {
        console.log(4, error);
        return Promise.reject(error);
  }
    );
    axios.get("https://www.baidwwu.COM").catch((error) =>
 {
      console.log(4, error);
}
    );
    // 2  Error: 888// 1  Error: 888// 3  Error: 888// 4  Error: 888// 5  Error: 888

先执行请求拦截器,后执行响应拦截器。

  • 设置多个请求拦截器的情况:后添加的拦截器先执行。
  • 设置多个响应拦截器的情况:按照设置顺序执行。

use() 方法的定义

先来看 use() 方法相关代码:

this.interceptors = {
  request: new InterceptorManager$1(),  response: new InterceptorManager$1(),}
    ;
VAR InterceptorManager = (function () {
  function InterceptorManager() {
        this.handlers = [];
  }
  // ...  // _createClass 方法可以给对象的原型上添加属性  _createClass(InterceptorManager, [    {
      key: "use",      value: 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;
      }
,    }
,    {
      key: "foreach",      value: function forEach(fn) {
        utils.forEach(this.handlers, function forEachHandler(h) {
          if (h !== null) {
                fn(h);
          }
        }
    );
      }
,    }
    ,    // ...  ]);
      return InterceptorManager;
}
    )();
    var InterceptorManager$1 = InterceptorManager;
    

可以看到 interceptors.requestinterceptors.response 各自指向 InterceptorManager 的实例。

InterceptorManager 原型上设置了 use() 方法,执行后给待执行队列 this.handlers 中添加一条数据。

这里利用了 this 的特性来区分作用域:谁调用 use() 方法就给谁的 handlers 中添加数据。在调用 use() 方法之后,已经将回调函数按顺序添加到了 handlers 数组中。

forEach() 方法用来遍历当前作用域 handlers 中不为 null 的元素,在执行拦截器时有用到,详情见下文。

拦截器如何执行

拦截器是在调用了 request() 方法前后执行的,先看相关源码:

var Axios = (function () {
  _createClass(Axios, [    {
      key: "request",      value: function request(configOrUrl, config) {
            // ...        // 初始化请求拦截器        var requestInterceptorChain = [];
            var synchronousRequestInterceptors = true;
        this.interceptors.request.forEach(function unshiftRequestInterceptors(          interceptor        ) {
              if (            tyPEof interceptor.runWhen === "function" &
    &
            interceptor.runWhen(config) === false          ) {
                return;
          }
              synchronousRequestInterceptors =            synchronousRequestInterceptors &
    &
     interceptor.synchronous;
              requestInterceptorChain.unshift(            interceptor.fulfilled,            interceptor.rejected          );
        }
    );
            // 初始化响应拦截器        var responseinterceptorChain = [];
        this.interceptors.response.forEach(function pushResponseInterceptors(          interceptor        ) {
              responseInterceptorChain.push(            interceptor.fulfilled,            interceptor.rejected          );
        }
    );
            var promise;
            var i = 0;
            var len;
        // 请求拦截器同步执行模式        if (!synchronousRequestInterceptors) {
              var chain = [dispatchRequest.bind(this), undefined];
              chain.unshift.apply(chain, requestInterceptorChain);
              chain.push.apply(chain, responseInterceptorChain);
              len = chain.length;
              promise = Promise.resolve(config);
              console.log(11, chain);
          while (i  len) {
                promise = promise.then(chain[i++]).catch(chain[i++]);
          }
              return promise;
        }
            // 请求拦截器异步执行模式        len = requestInterceptorChain.length;
            var newConfig = config;
            i = 0;
        while (i  len) {
              var onFulfilled = requestInterceptorChain[i++];
              var onRejected = requestInterceptorChain[i++];
          try {
                newConfig = onFulfilled(newConfig);
          }
 catch (error) {
                onRejected.call(this, error);
                break;
          }
        }
        try {
              promise = dispatchRequest.call(this, newConfig);
        }
 catch (error) {
              return Promise.reject(error);
        }
            i = 0;
            len = responseInterceptorChain.length;
        while (i  len) {
              promise = promise.then(            responseInterceptorChain[i++],            responseInterceptorChain[i++]          );
        }
            return promise;
      }
,    }
    ,  ]);
}
    )();
    

上面是相关的全部代码,下面进行分解。

拦截器回调方法的添加顺序

var requestInterceptorChain = [];
     // 请求拦截器执行链// 是否同步执行请求拦截器,每个拦截器都可以单独设置,但是只有所有拦截器都设置为true才为truevar synchronousRequestInterceptors = true;
this.interceptors.request.forEach(function unshiftRequestInterceptors(  interceptor) {
      // 传入 runWhen() 方法时,如果 runWhen() 方法返回值为 false 则忽略这个请求拦截器  if (    typeof interceptor.runWhen === "function" &
    &
    interceptor.runWhen(config) === false  ) {
        return;
  }
      // 是否同步执行  synchronousRequestInterceptors =    synchronousRequestInterceptors &
    &
     interceptor.synchronous;
      // 用 unshift() 添加数据,后设置的拦截器在前  requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
}
    );
    var responseInterceptorChain = [];
 // 响应拦截器执行链this.interceptors.response.forEach(function pushResponseInterceptors(  interceptor) {
      // 响应拦截器按顺序加在后面  responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
}
    );
    

interceptors.request.forEach() 的定义在上文提到过,封装为遍历自身的 handlers 数组,与数组的 forEach 类似,只是过滤了值为 null 的元素。

runWhen() 方法接收 config,返回 boolean,控制是否将当前拦截器的回调函数添加到执行链中。

请求拦截器用 unshift() 方法添加,所以后设置的先执行,响应拦截器用 push() 方法添加,所以按照设置顺序执行。

只要有一个拦截器的 synchronous 设置为 false,则 synchronousRequestInterceptors 的值为 false

同步执行请求拦截器(顺序执行)

synchronousRequestInterceptorsfalse 时为同步执行,相关逻辑如下:

var promise;
    var i = 0;
    var len;
if (!synchronousRequestInterceptors) {
      var chain = [dispatchRequest.bind(this), undefined];
     // 执行链  chain.unshift.apply(chain, requestInterceptorChain);
     // 将请求拦截器添加到请求之前  chain.push.apply(chain, responseInterceptorChain);
     // 将响应拦截器添加到响应之后  len = chain.length;
      promise = Promise.resolve(config);
  while (i  len) {
        promise = promise.then(chain[i++], chain[i++]);
 // 用 Promise 包装执行链  }
      return promise;
}
    

dispatchRequest() 是发送请求的方法。

同步执行模式下,会将执行链中的所有方法用 Promise 进行封装,前一个方法执行完毕后将其返回值作为参数传递给下一个方法。

这里的 chain 其实就是所有拦截器方法与请求方法合并而成的执行链,等价于: [...requestInterceptorChain, dispatchRequest.bind(this), ...responseInterceptorChain]

从一个例子来看 chain 的成员:

axios.interceptors.request.use(onFulfilled1, onRejected1);
    axios.interceptors.request.use(onFulfilled2, onRejected2);
    axios.interceptors.response.use(onFulfilled3, onRejected3);
    axios.interceptors.response.use(onFulfilled4, onRejected4);
    axios.get();
    // chain: [onFulfilled2, onRejected2, onFulfilled1, onRejected1, dispatchRequest, onFulfilled3, onRejected3, onFulfilled4, onRejected4]

在构建 Promise 链的时候,一次遍历中取了两个方法传递给 then():

promise = Promise.resolve(config);
while (i  len) {
      promise = promise.then(chain[i++], chain[i++]);
 // 用 Promise 包装执行链}
    return promise;
    

异步执行请求拦截器(同时执行)

var promise;
    var i = 0;
    var len = requestInterceptorChain.length;
     // 请求执行链的长度var newConfig = config;
    i = 0;
// 执行请求拦截器回调while (i  len) {
      var onFulfilled = requestInterceptorChain[i++];
     // use() 的第一个参数  var onRejected = requestInterceptorChain[i++];
 // use() 的第二个参数  // 执行成功后继续执行,执行失败后停止执行。  try {
        newConfig = onFulfilled(newConfig);
  }
 catch (error) {
        onRejected.call(this, error);
        break;
  }
}
// 执行发送请求方法try {
      promise = dispatchRequest.call(this, newConfig);
}
 catch (error) {
      return Promise.reject(error);
 // 执行失败后退出}
    // 执行响应拦截器回调i = 0;
    len = responseInterceptorChain.length;
while (i  len) {
      promise = promise.then(    responseInterceptorChain[i++], // use() 的第一个参数    responseInterceptorChain[i++] // use() 的第二个参数  );
}
    return promise;
    

dispatchRequest() 是发送请求的方法。

while 循环遍历所有的请求拦截器并调用,将执行语句包裹在 try-catch 语句中,只要有一个请求拦截器异常就停止循环。

可以看到在异步模式下,请求拦截器为异步执行,但是不影响发送请求,而响应拦截器还是在请求响应后同步执行。

Q& A

拦截器是如何工作的

调用 .request.use().response.use() 方法时,将传入的拦截器回调方法分别存入 请求拦截器回调数组响应拦截器回调数组

在调用 .get() 等方法时,将 请求拦截器回调数组响应拦截器回调数组 与发送请求的方法拼接成一个完整的执行链,按照同步或异步的模式调用执行链中的方法。

响应拦截器总是在返回响应结果后按顺序执行。

请求拦截器根据 synchronous 配置不同,行为有所不同:

  • 异步执行请求拦截器模式。
  • 没有设置 synchronous 时默认为异步执行请求拦截器模式,即遍历执行所有的请求拦截器一参回调,执行报错后停止遍历,并执行该拦截器的二参回调。
  • 同步执行请求拦截器模式。
  • 设置 synchronousfalse 时为同步执行请求拦截器模式,将执行链包装成一个 Promise 链顺序执行。

拦截器的执行顺序

先执行请求拦截器,后执行响应拦截器。

  • 设置多个请求拦截器的情况:后添加的拦截器先执行。
  • 设置多个响应拦截器的情况:按照设置顺序执行。

同步& 异步

计算机中的同步,指的是现实中的一步一步(同一时间只能干一件事),异步指的是同时进行(同一时间能干多件事)。

参考 npm axios

以上就是axios拦截器工作方式及原理源码解析的详细内容,更多关于axios拦截器工作原理的资料请关注其它相关文章!

您可能感兴趣的文章:
  • Typescript 封装 Axios拦截器方法实例
  • axios 拦截器管理类链式调用手写实现及原理剖析
  • vue cli+axios踩坑记录+拦截器使用方式,代理跨域proxy
  • vue中Axios添加拦截器刷新token的实现方法
  • Vue3 使用axios拦截器打印前端日志

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!


若转载请注明出处: axios拦截器工作方式及原理源码解析
本文地址: https://pptw.com/jishu/609321.html
Vue+echart 展示后端获取的数据实现 Vue实现docx/xlsx/pdf等类型文件预览功能

游客 回复需填写必要信息