跳到主要内容

拦截器 Interceptor (执行器,链式)

请求转换器(transformRequest)主要用来根据 data 格式,设置 http 请求头; 响应转换器(transformResponse)可以根据实际业务中服务端返回的数据格式,统一设置转换方法。 拦截器是被包装成了 Promise,显然主要是想用它来处理异步的。

汇总下就是: 转换器是处理数据和请求头的,不能处理异步,不会阻断请求和响应流程; 拦截器可以处理异步需求,可以使用拦截器阻断请求或响应流程。

拦截器

在请求或响应被 then 或 catch 处理前拦截它们。

export interface AxiosInterceptorManager<V> {
use<T = V>(onFulfilled?: (value: V) => T | Promise<T>, onRejected?: (error: any) => any, options?: AxiosInterceptorOptions): number;
eject(id: number): void;
}
export class Axios {
constructor(config?: AxiosRequestConfig);

defaults: AxiosDefaults;

interceptors: {
request: AxiosInterceptorManager<AxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse>;
};
...
}

axios 为我们提供了拦截器的功能,我们可以通过 use 方法在请求发出前处理 AxiosRequestConfig,也可以在请求返回后对 AxiosResponse 进行处理。从类型也可以看出,我们的拦截器必须接收与返回的类型必须一致,如果我们将请求的 AxiosRequestConfig 类型改变,那 axios 就无法正确的发送请求。

axios.interceptors.request.use (
AxiosRequestConfig((config) => {
// 在发送请求之前做些什么
return config;
});
)

希望能对请求的发送和响应做拦截,在发送请求之前和收到响应之后做额外逻辑 用 promise 实现 请求拦截器的 resolve 函数处理 config 对象,响应拦截器的 resolve 函数处理 response 对象,所以用泛型表示传进去的对象

import {ResolvedFn,RejectedFn} from '../types'

interface Interceptor<T> {
resolved: ResolvedFn<T>
rejected?: RejectedFn
}


export default class InterceptorManager<T>{
private interceptors: Array<Interceptor<T>|null>
constructor() {
this.interceptors = []
}

use(resolved:ResolvedFn<T>,rejected?: RejectedFn):number{
this.interceptors.push({
resolved,
rejected
})
return this.interceptors.length - 1
}

// 触发拦截器,没有在接口上定义,是因为只是给内部使用
// 可以和类接口定义不同,是因为只有供用户使用的需要类型标注
forEach(fn:(Interceptor:Interceptor<T>)=>void):void{
// 每次使用都会把manager中存的回调函数对取出来
// 然后根据fn类型,把回调加到请求拦截器或响应拦截器中
// 利用了执行器的思想
this.interceptors.forEach(inor=>{
if(inor!==null){
fn(inor)
}
})
}

eject(id:number):void{
if(this.interceptors[id]){
this.interceptors[id] =null
}
}
}

拦截器链式调用实现

interface Interceptors{
// 请求拦截器的管理者
request: InterceptorManager<AxiosRequestConfig>
// 响应拦截器的管理者
response: InterceptorManager<AxiosResponse>
}


request(url: any, config?: AxiosRequestConfig):AxiosPromise{
if(typeof url === 'string'){
if(!config){
config= {url}
}
} else {
config = url
}

// 所有的请求拦截器,初始携带了一个,就是最后的发起请求
const chain:PromiseChain<any>[] = [
{resolved:dispatchRequest,
rejected:undefined}
]

// request(管理者)加到调用链的前面
this.interceptors.request.forEach(intor =>{
chain.unshift(intor)
})


// reponse(管理者)加到后面
this.interceptors.response.forEach(intor =>{
chain.push(intor)
})

// 就算啥都没有也会有一个内容为config的promise
let promise = Promise.resolve(config)

while(chain.length){
// 由于promise.then执行后已经加入到微任务队列
// 所以这个循环执行完后的promise实际上等价于promsie.then.then.then....队列里的
// (resolved,rejected)
const {resolved,rejected} = chain.shift()!
promise = promise.then(resolved,rejected)
}

return promise
}


export interface AxiosInterceptorManager<T> {
// 通过use函数,添加拦截器函数,返回编号,删除用
use(resolved: ResolvedFn<T>,rejected:RejectedFn):number

eject(id: number) :void
}

export interface ResolvedFn<T> {
// 拦截器可以异步初始化,所以返回promise
(val: T):T | Promise<T>
}

export interface RejectedFn{
(error:any): any
}