背景:
request的封装通常是一个项目中不可或缺的部分,不管是基于xhr,fetch,rxjs,axios... 关于竞态上的处理是一个很值得考虑的方面,看了网上一些处理方法,大致有:
防抖、设置loading或锁状态、中断之前的请求。但一个系统里面,业务场景多种多样,不能说用哪一种能解决所有场景,只能按需使用,个人做法是防抖和锁状态在业务代码里处理,中断请求通过request的封装扩展字段处理,因为也不是所有接口都一刀切用中断请求,所以需要通过配置来适配同一接口是否需要中断,一般来说像表格数据接口,详情数据接口等适合中断请求的设定。这里就主要介绍axios的中断请求扩展。
关于AbortController
AbortController
AbortController 接口表示一个控制器对象,允许你根据需要中止一个或多个 Web 请求。
构造函数
AbortController.AbortController()
创建一个新的 AbortController 对象实例。
属性
返回一个 AbortSignal 对象实例,可以用它与一个 DOM 请求进行通信或者中止该请求。
方法
中止一个尚未完成的 Web(网络)请求。这能够中止 fetch 请求及任何响应体的消费和流。
思路:为每个配置了isSignal:true的请求创建一个
AbortController实例,并将其添加到请求配置中,以便我们可以随时取消请求。
requestInterceptors设置:
request.isSignal && axiosCanceler.addPending(response);
responseInterceptors设置: response.config.isSignal && axiosCanceler.removePending(response.config);
关于axios的封装:
import { getLocale, history } from '@umijs/max';
import { message } from 'antd';
import { first, get, set } from 'lodash';
import * as NProgress from 'nprogress';
import queryString from 'query-string';
import { AxiosCanceler } from './axiosCancel';
import { EN_LANG } from './locales';
import translate from './locales/translate';
import { storage } from './utils/tzStorage';
NProgress.configure({
easing: 'linear',
speed: 350,
showSpinner: false,
});
const codeMessage: Record<number, string> = {
200: translate('request.code.200'),
201: translate('request.code.201'),
202: translate('request.code.202'),
204: translate('request.code.204'),
400: translate('request.code.400'),
401: translate('request.code.401'),
403: translate('request.code.403'),
404: translate('request.code.404'),
406: translate('request.code.406'),
410: translate('request.code.410'),
422: translate('request.code.422'),
500: translate('request.code.500'),
502: translate('request.code.502'),
503: translate('request.code.503'),
504: translate('request.code.504'),
};
const axiosCanceler = new AxiosCanceler();
const errorHandler = (error: any) => {
const { response } = error ?? {};
if (response?.status) {
const errorText = codeMessage[response.status] || response.statusText;
const { status } = response;
const errorTxt = `${(response?.data as any)?.message || errorText}`;
if (typeof response?.data !== 'string') {
if ([401, 503].includes(status)) {
storage.remove('userInfo');
storage.clearCookie();
}
status === 401 && history.replace('/login');
status === 503 && history.replace('/503');
message.error({
key: status === 401 ? status : +new Date(),
content: errorTxt,
});
return response;
}
message.error({
key: first(`${response.status}`) === '5' ? status : +new Date(),
content: errorTxt,
});
} else if (!response) {
// console.log(response);
// message.error(translate('request.errorTip'));
}
return response;
};
const requestInterceptors = (request: {
isSignal?: boolean;
headers: { Authorization: string };
}) => {
request.isSignal && axiosCanceler.addPending(request);
const token = storage.getCookie('token');
const lang = getLocale();
if (token) request.headers.Authorization = `Bearer ${token}`;
const contentType = get(request, ['headers', 'Content-Type']);
!contentType && set(request, ['headers', 'Content-Type'], 'application/json');
set(request, ['headers', 'Accept-Language'], lang === EN_LANG ? 'en' : 'zh');
NProgress.start();
return request;
};
const responseInterceptors = (response: any) => {
response.config.isSignal && axiosCanceler.removePending(response.config);
NProgress.done();
const {
data,
config: { customHandleRes },
} = response;
if (customHandleRes) {
return response;
}
const { code } = data;
if (!code) {
return response.data;
}
return Promise.reject(response);
};
export const requestConfig = {
paramsSerializer(params: any) {
return queryString.stringify(params);
},
errorConfig: {
errorHandler,
},
timeout: 100 * 1000,
baseURL: process.env.PUBLIC_URL,
// 请求拦截器
requestInterceptors: [requestInterceptors],
// 响应拦截器
responseInterceptors: [
[
responseInterceptors,
(error: any) => {
const { config, response } = error;
NProgress.done();
if (!config?.skipErrorHandler) {
errorHandler(error);
}
return Promise.reject(response?.data);
},
],
],
};
AxiosCanceler类将是一个非常有用的工具。它可以让你更好地控制你的异步请求,并避免一些不必要的错误。完整代码示例:celeris-admin/packages/web/request/src at master · kirklin/celeris-admin (github.com)
参考文章: