- 取消重复请求: 完全相同的接口在上一个pending状态时,自动取消下一个请求
- 请求失败自动重试: 接口请求后台异常时候,自动重新发起多次请求,直到达到所设次数
- 请求接口数据缓存:接口在设定时间内不会向后台获取数据,而是直接拿本地缓存
cancelRequest: true // 接口中定义该项则开启取消重复请求功能
retry: 3, retryDelay: 1000 // retry 请求重试次数,retryDelay 两次重试之间的时间间隔
cache: true, setExpireTime: 30000 // cache: true 开启当前接口缓存,setExpireTime 当前接口缓存时限
取消重复请求
完全相同的接口在上一个 pedding 状态时,自动取消下一个请求
- 在请求拦截器判断 pendingRequestMap 是否存在当前请求的 key,不存在则把当前请求信息添加到 pendingRequestMap 对象中.
export const generateReqKey = (config) => {
// 响应的时候,response.config 中的 data 是一个JSON字符串,所以需要转换一下
if (config && config.data && isJsonStr(config.data)) {
config.data = JSON.parse(config.data);
}
const { method, url, params, data } = config; // 请求方式,参数,请求地址,
return [method, url, Qs.stringify(params), Qs.stringify(data)].join('&'); // 拼接
}
export const addPendingRequest = (config) => {
if (config.cancelRequest) {
const requestKey = getRequestKey(config)
if (peddingRequest.has(requestKey)) {
config.cancelToken = new Axios.CancelToken(cancel => {
// cancel 函数的参数会作为 promise 的 error 被捕获
cancel(`${config.url} 请求已取消`)
})
} else {
config.cancelToken = config.cancelToken ||
new Axios.CancelToken(cancel => {
peddingRequest.set(requestKey, cancel)
})
}
}
}
- 响应拦截器正常时从 pendingRequest 对象中移除请求,
// removePendingRequest:检查是否存在重复请求,若存在则取消已发的请求。
export function removePendingRequest(response) {
if (response && response.config && response.config.cancelRequest) {
const requestKey = generateReqKey(response.config);
// 判断是否有这个 key if (pendingRequest.has(requestKey)) {
const cancelToken = pendingRequest.get(requestKey);
cancelToken(requestKey);
pendingRequest.delete(requestKey);
}
}
}
请求失败自动重试
接口请求后台异常时候,自动重新发起多次请求,直到达到所设次数
响应拦截器如果 error,从 pendingRequest 对象中移除请求,如果请求未被取消,则重新发起请求
// 实现 请求错误时重新发送接口
import { isJsonStr } from './commonFuns';
/**
* @param {失败信息} err
* @param {实例化的单例} axios
* @returns
*/
export function againRequest(err, axios) {
let config = err.config;
// config.retry 具体接口配置的重发次数
if (!config || !config.retry) return Promise.reject(err);
// 设置用于记录重试计数的变量 默认为0
config.__retryCount = config.__retryCount || 0;
// 判断是否超过了重试次数
if (config.__retryCount >= config.retry) {
return Promise.reject(err);
}
// 重试次数
config.__retryCount += 1;
// 延时处理
var backoff = new Promise(function(resolve) {
setTimeout(function() {
resolve();
}, config.retryDelay || 1000);
});
// 重新发起axios请求
return backoff.then(function() {
// 判断是否是JSON字符串
// TODO: 未确认config.data再重发时变为字符串的原因
if (config.data && isJsonStr(config.data)) {
config.data = JSON.parse(config.data);
}
return axios(config);
});
}
请求缓存
接口在设定时间内不会向后台获取数据,而是直接拿本地缓存。通过回调 cancel 方法 cancel(cacheData) 传递结果到 catch 中。例如:
axios.post("/test/list").then(() => {
}).catch(() => {
// 此处接收缓存的数据
)
export function requestInterceptor(config, axios) {
// 开启缓存则保存请求结果和cancel 函数
if (config.cache) {
let data = CACHES[`${generateReqKey(config)}`];
// 这里用于存储是默认时间还是用户传递过来的时间
let setExpireTime;
config.setExpireTime ? (setExpireTime = config.setExpireTime) : (setExpireTime = options.expire);
// 判断缓存数据是否存在 存在的话 是否过期 没过期就返回
if (data && getNowTime() - data.expire < setExpireTime) {
config.cancelToken = new Axios.CancelToken(cancel => {
// cancel 函数的参数会作为 promise 的 error 被捕获
cancel(data);
}); // 传递结果到catch中
}
}
}
export function responseInterceptor(response) {
// 返回的code === 200 时候才会缓存下来
if (response && response.config.cache && response.data.code === 200) {
let data = {
expire: getNowTime(),
data: response
};
CACHES[`${generateReqKey(response.config)}`] = data;
}
}