我看了很多 axios 的封装,但是我感觉他们的封装。也不够自由,主要是写完之后,如果以后有东西需要修改的时候,还要回去拦截器进行修改。但是有一些东西拦截器可能是你以后的业务需求才需要添加的。
我就在想我能不能拦截器做成插件式的模式进行动态配置呢?例如下面的效果,点击添加一个请求缓存器,请求的时候就读缓存。当然你也可以去掉直接到达效果。
实现这个功能我这需要下面的做法,就可以实现动态控制我们的 axios 来扩展请求业务。
this.interceptors.push(new xxxInterceptors());
如何进行考虑设计
首先为了让我们的系统拥有扩展性,我这里会先定义一个 IRequest interface,为以后要做的事情进行约束。我们平时使用 request 用的比较多就是只有 4 大请求方法。定义好接口之后,就是我们的实现方式了。
这样我们就可以把我们 node.js、fetch、小程序的 request 都实现然后给到系统调用层调用,他们不需要知道怎么实现,他们只需要知道我用什么类型的 Request 就 new 那个对象来进行使用即可。
在这个过程中,我们需要对 axios 进行重复请求处理。这个时候我需要一个 cache 来进行缓存。这一类的文章多得是,我和他们的做法不一样在于,我是使用 ES6 的 Map 做的 key,value 存储。我坚持使用 oop 去实现。React 除了视图使用 FC 模式去编写,处理业务的地方我还是推荐使用 oop 模式编码。
class AxiosHttpClient {
private okHttp: AxiosInstance;
private CancelToken = axios.CancelToken;
private EXPIRE_TIME = 60000;
private cache: Map<string | undefined, any> = new Map();
public constructor() {
this.okHttp = axios.create({ timeout: 10000, responseType: 'json' })
this.okHttp.interceptors.request.use(config => {
config = this.handleRequestCacheDoCacen(config);
return config;
})
this.okHttp.interceptors.response.use(
response => {
response = this.handleResonseCacheDoCacen(response);
return response;
},
err => {
//已经取消的请求,我们需要把message 调到 response resolve里面进行正常的调用
if (axios.isCancel(err)) {
return Promise.resolve(err.message);
}
return Promise.reject(err);
}
)
}
/**
* 是否存在cache,如果存在取消请求
*/
public handleRequestCacheDoCacen(config: AxiosRequestConfig<any>) {
let source = this.CancelToken.source();
config.cancelToken = source.token;
let data = this.cache.get(config.url);
if (data && GetTimeNowUnxi() - data.expire < this.EXPIRE_TIME) {
source.cancel(data);
}
return config;
}
/**
* 从缓存中获取Cache Data
* @param response
* @returns
*/
public handleResonseCacheDoCacen(response: AxiosResponse<any>) {
let data = {
expire: GetTimeNowUnxi(),
data: response.data
};
this.cache.set(`${response.config.url}`, data)
return response;
}
public getHttpClient() {
return this.okHttp;
}
}
但是我写完后,发现interceptors
就无法继续扩展了。如果后续需要维护我还得可能还要来这里进行修改。或者写以下 if 开关来处理逻辑。
这个时候你有很多种做法,用一个 Object/Array 来管理你的要做事情的handle
,在interceptors
里面进行for in
/ for of
操作,这种做法类似与 pipe 流水线操作。不过我是偏向使用 rxjs 来做这种事情,但是前端按着发展速度,我不知道什么时候才有人意识到 rxjs。了解了 rxjs 后你会发现你那些vuex
,dva
,mobx
等都是啥玩意。
为了照顾大多数前端,我这边设计使用的是观察者模式来实现interceptors
热插槽处理。于是就有以下操作。
// index.js
class AxiosHttpClient {
private okHttp: AxiosInstance;
private CancelToken = axios.CancelToken;
private $interceptorSubject: InterceptorSubject;
private cache: Map<string | undefined, any> = new Map();
private interceptors: Observer[] = []
private static instance: AxiosHttpClient;
public static getInstance() {
if (!this.instance) {
this.instance = new AxiosHttpClient();
}
return this.instance;
}
public constructor() {
this.$interceptorSubject = new AxiosInterceptorSubject();
this.okHttp = axios.create({ timeout: 10000, responseType: 'json' })
}
public getHttpClient() {
this.okHttp.interceptors.request.use(config => {
if (this.interceptors.length > 0) {
for (let interceptor of this.interceptors) {
this.$interceptorSubject.attach(interceptor);
}
config = this.$interceptorSubject.notifyRequest(config);
}
return config;
})
this.okHttp.interceptors.response.use(
response => {
console.log(this.interceptors);
if (this.interceptors.length > 0) {
response = this.$interceptorSubject.notifyResponse(response);
}
return response;
},
err => {
//已经取消的请求,我们需要把message 调到 response resolve里面进行正常的调用
if (axios.isCancel(err)) {
return Promise.resolve(err.message);
}
return Promise.reject(err);
}
)
return this.okHttp;
}
public setCache(key: string, value: any) {
this.cache.set(key, value);
}
public getCache(key: string | undefined) {
return this.cache.get(key);
}
public getCancelToken() {
return this.CancelToken;
}
public setInterceptorsObserver(ob: Observer) {
this.interceptors.push(ob);
}
public removeInterceptorSubject(ob: Observer) {
this.$interceptorSubject.detach(ob);
const observerIndex = this.interceptors.indexOf(ob);
this.interceptors.splice(observerIndex, 1);
}
}
接口的定义
export interface InterceptorSubject {
attach(observer: Observer): void;
detach(observer: Observer): void;
notifyRequest(config: AxiosRequestConfig): any;
notifyResponse(response: AxiosResponse): any;
}
export interface Observer {
update(config: AxiosRequestConfig): any;
doResponse(config: AxiosResponse): any;
}
具体的实现类
import { AxiosRequestConfig, AxiosResponse } from 'axios';
import { AxiosHttpClient, EXPIRE_TIME } from 'core/request/unitys/axios';
import { GetTimeNowUnxi } from 'core/time';
import { Observer } from './InterceptorSubject';
export class AxiosCacheInterceptor implements Observer {
private app = AxiosHttpClient.getInstance();
update(config: AxiosRequestConfig): any {
let source = this.app.getCancelToken().source();
config.cancelToken = source.token;
let data = this.app.getCache(config.url);
if (data && GetTimeNowUnxi() - data.expire < EXPIRE_TIME) {
source.cancel(data);
}
return config;
}
doResponse(response: AxiosResponse<any, any>) {
let data = {
expire: GetTimeNowUnxi(),
data: response.data
};
this.app.setCache(`${response.config.url}`, data)
return response;
}
}
然后再 App 的 main.ts 入口文件,把我需要的业务代码都注入到Subject
里面进行调用监听。
我们现在就可以通过业务来动态控制我们的 axios 了...
标签:axios,return,data,前端,interceptors,封装,config,response From: https://www.cnblogs.com/wp-leonard/p/17839024.html