[axios] interceptors 实现原理
2019-12-25 本文已影响0人
小黄人get徐先生
官网链接:interceptors
你可以拦截请求或者响应在它们被 then
方法或者 catch
方法处理之前。
// 添加一个请求拦截器
axios.interceptors.request.use(function (config) {
// 请求发送前的处理
return config;
}, function (error) {
// 请求发送错误的处理
return Promise.reject(error);
});
// 添加一个响应拦截器
axios.interceptors.response.use(function (response) {
// 2xx 状态码的情况将触发这个函数的执行,处理响应数据
return response;
}, function (error) {
// 非 2xx 状态码情况将触发这个函数,处理响应错误
return Promise.reject(error);
});
也可以移除之前添加的拦截器:
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
实现
types/index.ts
export interface ResolvedFn<T> {
(val: T): T | Promise<T>
}
export interface RejectedFn {
(error: any): any
}
core/interceptorManager.ts
import { RejectedFn, ResolvedFn } from '../types'
interface Interceptor<T> {
resolved: ResolvedFn<T>
rejected?: RejectedFn
}
// 拦截管理器类,这里使用 T 类型是因为请求拦截器是 resovle 方法处理配置(AxiosRequestConfig),响应拦截器 resolve 方法处理响应数据( AxiosResponse )
export default class InterceptorManager<T> {
private interceptors: Interceptor<T>[];
constructor() {
this.interceptors = [];
}
// 添加拦截器
use(resolved: ResolvedFn<T>, rejected?: RejectedFn): number {
this.interceptors.push({
resolved,
rejected
});
return this.interceptors.length - 1;
}
// 遍历拦截器,并执行 fn 方法
forEach(fn: (interceptor: Interceptor<T>) => void): void {
this.interceptors.forEach(interceptor => {
if (interceptor !== null) {
fn(interceptor);
}
});
}
// 移除拦截器
eject(id: number): void {
if (this.interceptors[id]) {
this.interceptors[id] = null;
}
}
}
core/Axios.ts
import { AxiosPromise, AxiosRequestConfig, AxiosResponse, RejectedFn, ResolvedFn } from '../types'
import dispatchRequest from './dispatchRequest'
import InterceptorManager from './interceptorManager'
import mergeConfig from './mergeConfig'
interface Interceptors {
request: InterceptorManager<AxiosRequestConfig>
response: InterceptorManager<AxiosResponse>
}
interface PromiseChain<T> {
resolved: ResolvedFn<T> | ((config: AxiosRequestConfig) => AxiosPromise<T>)
rejected?: RejectedFn
}
export default class Axios {
defaults: AxiosRequestConfig; // 默认配置相关,可以不用关心
interceptors: Interceptors;
constructor(initConfig: AxiosRequestConfig) {
this.defaults = initConfig; // 默认配置相关,可以不用关心
this.interceptors = {
request: new InterceptorManager<AxiosRequestConfig>(),
response: new InterceptorManager<AxiosResponse>()
};
}
request(url: any, config?: any): AxiosPromise {
// 重载实现
if (typeof url === 'string') {
if (!config) {
config = {};
}
config.url = url;
} else {
config = url;
}
// 配置合并相关,这里不用关心
config = mergeConfig(this.defaults, config);
// 初始化链式调用列表如下,然后通过 interceptorManager 的 forEach 在列表前(request)或列表后(response)填完拦截器方法
// request interceptor -> request interceptor -> dispatchRequest -> response interceptor -> response interceptor
const chain: PromiseChain<any>[] = [{
resolved: dispatchRequest,
rejected: undefined
}];
// 头加方式添加请求拦截器到 chain 中
this.interceptors.request.forEach(interceptor => {
chain.unshift(interceptor);
});
// 尾加方式添加响应拦截器到 chain 中
this.interceptors.response.forEach(interceptor => {
chain.push(interceptor)
});
let promise = Promise.resolve(config);
// 链式调用
while (chain.length) {
const { resolved, rejected } = chain.shift()!;
promise = promise.then(resolved, rejected);
}
return promise;
}