文章目录
- 一、拦截器 interceptor
- 1、创建 InterceptorManager.js 文件
- 2、Axios 中实例化 InterceptorManager 类
- 3、总结
在本系列的第一篇章节 手写axios源码系列一:axios核心知识点 中已经介绍过一些拦截器的基础知识,可知拦截器分为:
- 请求拦截器:axios.interceptors.request
- 响应拦截器:axios.interceptors.response
使用 use 方法添加拦截器,并且可以添加多个拦截器。use 方法接收两个函数为参数:
- fulfilled:传递给 promise.then() 的第一个成功的回调
- rejected:传递给 promise.then() 的第二个失败的回调
use 使用方式如下:
axios.interceptors.request.use(fulfilled, rejected)
axios.interceptors.response.use(fulfilled, rejected)
一、拦截器 interceptor
1、创建 InterceptorManager.js 文件
export default class InterceptorManager {
constructor(){
// 因为拦截器可以添加多个,所以用数组保存
this.handlers = [];
},
// 原型对象的 use 方法
use(fulfilled, rejected){
this.handlers.push({ fulfilled, rejected })
}
}
2、Axios 中实例化 InterceptorManager 类
在发送请求前,需要处理请求拦截器,而响应之后需要处理响应拦截器,最后再返回处理过后的响应数据;所以拦截器的处理逻辑放在 Axios.prototype.request 方法中。
import InterceptorManager from "./InterceptorManager.js";
export default class Axios {
constructor(config){
this.defaults = config;
this.interceptors = {
request: new InterceptorManager(), // 实例化请求拦截器
response: new InterceptorManager() // 实例化响应拦截器
}
}
request(configOrUrl, config){
if(typeof configOrUrl === "string"){
config.url = configOrUrl
} else {
config = {
...configOrUrl,
...config
}
}
// 将 config包装为一个成功状态的 promise对象
let promise = Promise.resolve(config);
// 创建执行链,这里调用 dispatchRequest方法以发送请求,undefined起到一个占位符的作用
const chain = [dispatchRequest, undefined];
/** 拦截器的处理逻辑 */
// 将请求拦截器添加到 chain的头部
this.interceptors.request.handlers.forEach(interceptor => {
chain.unshift(interceptor.fulfilled, interceptor.rejected)
});
// 将响应请求器添加到 chain的尾部
this.interceptors.response.handlers.forEach(interceptor => {
chain.push(interceptor.fulfilled, interceptor.rejected)
});
// 执行所有的拦截器(一个成功,一个失败)
while(chain.length){
promise = promise.then(chain.shift(), chain.shift());
}
// 发送请求后返回的是一个 promise对象
return promise;
}
如果有2个请求拦截器,2个响应拦截器,则拦截器整体添加流程如下图:
执行链 chain 执行时是从数组索引0开始执行的,所以先执行 请求拦截器2
,再执行请求拦截器1
,然后执行 dispatchRequest
发送请求,请求响应后执行 响应拦截器1
,响应拦截器2
,最后返回 response
。
3、总结
拦截器这里的逻辑其实就是将拦截器添加到数组的方式不同,所以产生的结果也不同,明白 unshift 与 push 将数据添加到数组的方式,也就明白拦截器的执行方式了。后面执行链执行时,使用 shift 从 chain 中取数据,会改变 chain 的长度,明白这些点也就难不住你了。so easy。
还有一点,就是声明执行链 chain 时,有一个 undefined
占位符。原因就是 promise.then(chain.shift(), chain.shift())
代码执行时,每次从 chain 中取出成对的回调函数,一个成功,一个失败,放到相应的位置执行。如果没有 undefined
占位,当取到 dispatchRequest
回调函数时,下一个取的就是 响应成功1
的回调函数放到 then
中失败回调的位置,导致响应出错。这里为了保证程序的正确运行,所以使用了 undefined
占位。