axios源码解析 - 请求拦截器
axios请求拦截器,也就是在请求发送之前执行自定义的函数。
axios源码版本 - ^0.27.2 (源码是精简版)
平时在业务中会这样去写请求拦截器,代码如下:
// 创建一个新的实例 var service = axios.create(); // 请求拦截器 service.interceptors.request.use((config) => { // 请求头加token config.headers['token'] = 'xxx'; ... ... ... return config; }, (err) => { return Promise.reject(err); });
其中 service.interceptors.request.use 方法起到了作用,其核心源码如下:
/* axios/lib/core/Axios.js */ // Axios构造函数 function Axios(defaultConfig) { this.defaults = defaultConfig; this.interceptors = { request: new InterceptorManager(), response: new InterceptorManager() } } /* axios/lib/core/InterceptorManager.js */ // InterceptorManager构造函数 function InterceptorManager() { // 默认空数组 this.handlers= []; } // InterceptorManager原型上定义use方法 (上述业务中的use方法,其实就是调用了该方法) InterceptorManager.prototype.use = function(fulfilled, rejected) { // 数组中push一个包含成功回调、失败回调的对象 this.handlers.push({ fulfilled: fulfilled, rejected: rejected }); // 返回数组长度 - 1 return this.handlers.length - 1; } // InterceptorManager原型上定义eject方法 InterceptorManager.prototype.eject = function(id) { if (this.handlers[id]) { this.handlers[id] = null; } } // InterceptorManager原型上定义forEach方法 InterceptorManager.prototype.forEach = function(fn) { utils.forEach(this.handlers, function(h) { if (h !== null) { fn(h); } }); }
service.interceptors.request.use 原来就是向handlers数组push了一个对象,可打印信息查看,代码如下:
console.log(service.interceptors.request.handlers); // 结果如下 [ { fulfilled: (config) => {...}, rejedcted: (err) => {...} } ]
那么,在发送请求时,请求拦截器是如何运作的,代码如下:
/* axios/lib/core/Axios.js */ Axios.prototype.request = function(defaultConfigOrUrl, config) { ... ... ... var requestInterceptorChain = []; this.interceptors.request.forEach(function (interceptor) { // 将该实例的this.interceptors.request.handlers放入requestChain requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected); }); var promise; // dispatchRequest就是请求过程 var chain = [dispatchRequest, undefined]; Array.prototype.unshift.apply(chain, requestInterceptorChain); promise = Promise.resolve(config); while (chain.length) { // 链式调用,不断减少chain数组的长度,直至为空 promise = promise.then(chain.shift(), chain.shift()); } return promise; ... ... ... }
这也便是说为什么axios是基于promise的,请求拦截器 --> 请求 --> 响应拦截器。
取消拦截器
取消拦截器功能,我觉得作用不大,代码如下:
var requestNumber = service.interceptors.request.use(fulfilled, rejected); // 取消请求拦截器 service.interceptors.request.reject(requestNumber); service.post({})
多个请求拦截器
主要讲多个请求拦截器的执行顺序,代码如下:
// 第一个请求拦截器 service.interceptors.request.use(fulfilled1, rejected1); // 第二个请求拦截器 service.interceptors.request.use(fulfilled2, rejected2); // 第三个请求拦截器 service.interceptors.request.use(fulfilled3, rejected3); // 根据上述Axios.prototype.request方法,可以知道handlers数组:[fulfilled3, rejected3, fulfilled2, rejected2, fulfilled1, rejected1] // 所以执行顺序:fulfilled3 --> fulfilled2 --> fulfilled1