axios|axios 拦截器管理类链式调用手写实现及原理剖析
目录
- axios库的拦截器使用
- 整体设计
- 拦截器管理类实现
- 接口定义
- 代码实现
- 链式调用实现
axios库的拦截器使用 我们知道
axios
库的拦截器的使用方式如下:// 添加一个请求拦截器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
和 response
2 个属性,它们都有一个 use
方法,use
方法支持 2 个参数,第一个参数类似 Promise.then
的 resolve
函数,第二个参数类似 Promise.then
的 reject
函数。我们可以在 resolve
函数和 reject
函数中执行同步代码或者是异步代码逻辑。并且我们是可以添加多个拦截器的,拦截器的执行顺序是链式依次执行的方式。对于
request
拦截器,后添加的拦截器会在请求前的过程中先执行;对于 response
拦截器,先添加的拦截器会在响应后先执行。axios.interceptors.request.use(config => {config.headers.test += '1'return config})axios.interceptors.request.use(config => {config.headers.test += '2'return config})
此外,我们也可以支持删除某个拦截器,如下:
const myInterceptor = axios.interceptors.request.use(function () {/*...*/})axios.interceptors.request.eject(myInterceptor)
整体设计 我们先用一张图来展示一下拦截器工作流程:
文章图片
整个过程是一个链式调用的方式,并且每个拦截器都可以支持同步和异步处理,我们自然而然地就联想到使用 Promise 链的方式来实现整个调用过程。
在这个 Promise 链的执行过程中,请求拦截器
resolve
函数处理的是 config
对象,而相应拦截器 resolve
函数处理的是 response
对象。在了解了拦截器工作流程后,我们先要创建一个拦截器管理类,允许我们去添加 删除和遍历拦截器。
拦截器管理类实现 根据需求,
axios
拥有一个 interceptors
对象属性,该属性又有 request
和 response
2 个属性,它们对外提供一个 use
方法来添加拦截器,我们可以把这俩属性看做是一个拦截器管理对象。use
方法支持 2 个参数,第一个是 resolve
函数,第二个是 reject
函数,对于 resolve
函数的参数,请求拦截器是 AxiosRequestConfig
类型的,而响应拦截器是 AxiosResponse
类型的;而对于 reject
函数的参数类型则是 any
类型的。根据上述分析,我们先来定义一下拦截器管理对象对外的接口。
接口定义
【axios|axios 拦截器管理类链式调用手写实现及原理剖析】这里我们定义了
AxiosInterceptorManager
泛型接口,因为对于 resolve
函数的参数,请求拦截器和响应拦截器是不同的。export interface AxiosInterceptorManager{use(resolved: ResolvedFn , rejected?: RejectedFn): numbereject(id: number): void}export interface ResolvedFn {(val: T): T | Promise }export interface RejectedFn {(error: any): any}
代码实现
import { ResolvedFn, RejectedFn } from '../types'interface Interceptor{resolved: ResolvedFn rejected?: RejectedFn}export default class InterceptorManager {private interceptors: Array | null>constructor() {// 拦截器数组this.interceptors = []}// 收集拦截器use(resolved: ResolvedFn , rejected?: RejectedFn): number {this.interceptors.push({resolved,rejected})return this.interceptors.length - 1}// 遍历用户写的拦截器,并执行fn函数把拦截器作为参数传入forEach(fn: (interceptor: Interceptor ) => void): void {this.interceptors.forEach(interceptor => {if (interceptor !== null) {fn(interceptor)}})}eject(id: number): void {if (this.interceptors[id]) {// 置为null,不能直接删除this.interceptors[id] = null}}}
我们定义了一个
InterceptorManager
泛型类,内部维护了一个私有属性 interceptors
,它是一个数组,用来存储拦截器。该类还对外提供了 3 个方法,其中 use
接口就是添加拦截器到 interceptors
中,并返回一个 id
用于删除;forEach
接口就是遍历 interceptors
用的,它支持传入一个函数,遍历过程中会调用该函数,并把每一个 interceptor
作为该函数的参数传入;eject
就是删除一个拦截器,通过传入拦截器的 id
删除。链式调用实现 当我们实现好拦截器管理类,接下来就是在
Axios
中定义一个 interceptors
属性,它的类型如下:interface Interceptors {request: InterceptorManagerresponse: InterceptorManager}export default class Axios {interceptors: Interceptorsconstructor() {this.interceptors = {request: new InterceptorManager(),response: new InterceptorManager()}}}
Interceptors
类型拥有 2 个属性,一个请求拦截器管理类实例,一个是响应拦截器管理类实例。我们在实例化 Axios
类的时候,在它的构造器去初始化这个 interceptors
实例属性。接下来,我们修改
request
方法的逻辑,添加拦截器链式调用的逻辑:interface PromiseChain {resolved: ResolvedFn | ((config: AxiosRequestConfig) => AxiosPromise)rejected?: RejectedFn}request(url: any, config?: any): AxiosPromise {if (typeof url === 'string') {if (!config) {config = {}}config.url = url} else {config = url}// 定义一个数组,这个数组就是要执行的任务链,默认有一个真正发送请求的任务const chain: PromiseChain[] = [{resolved: dispatchRequest,rejected: undefined}]// 把用户定义的请求拦截器存放到任务链中,请求拦截器最后注册的最先执行,所以使用unshift方法this.interceptors.request.forEach(interceptor => {chain.unshift(interceptor)})// 把响应拦截器存放到任务链中this.interceptors.response.forEach(interceptor => {chain.push(interceptor)})// 利用config初始化一个promiselet promise = Promise.resolve(config)// 遍历任务链while (chain.length) {// 取出任务链的首个任务const { resolved, rejected } = chain.shift()!// resolved的执行时机是就是上一个promise执行resolve()的时候,这样就形成了链式调用promise = promise.then(resolved, rejected)}return promise}
首先,构造一个
PromiseChain
类型的数组 chain
,并把 dispatchRequest
函数赋值给 resolved
属性;接着先遍历请求拦截器插入到 chain
的前面;然后再遍历响应拦截器插入到 chain
后面。接下来定义一个已经 resolve 的
promise
,循环这个 chain
,拿到每个拦截器对象,把它们的 resolved
函数和 rejected
函数添加到 promise.then
的参数中,这样就相当于通过 Promise 的链式调用方式,实现了拦截器一层层的链式调用的效果。注意我们拦截器的执行顺序,对于请求拦截器,先执行后添加的,再执行先添加的;而对于响应拦截器,先执行先添加的,后执行后添加的。
以上就是axios 拦截器管理类链式调用手写实现及原理剖析的详细内容,更多关于axios 拦截器管理类链式调用的资料请关注脚本之家其它相关文章!
推荐阅读
- 游戏服务器中的Netty应用以及源码剖析
- Linux服务器VPS的Windows|Linux服务器VPS的Windows DD包详细的制作教程
- 投稿|打破垄断密集上市,强生、威高纷纷圈地,手术机器人成骨科顶流
- 携手共建云原生生态 阿里云云原生加速器第二次集结圆满结营
- 容器化 | 使用 Alpine 构建 Redis 镜像
- 行业应用场景|敢不敢和佳信文本机器人PK,你和它哪个更高情商~
- 后端|【python】Jenkins实现携带commit_log钉钉/企微机器人通知
- 【服务器存储数据恢复】HP-Lefthand存储数据恢复案例
- 自然语言处理|机器学习_TF-IDF逆文本频率指数
- springboot+mybatis拦截器方法实现水平分表操作