axios是什么,无需多讲,axios解析的可以看下77.9K Star 的 Axios 项目有哪些值得借鉴的地方这篇文章
项目中,经常会有很多用户的网络抽风或者各种原因造成偶发性的网络异常请求错误,如果没有重试机制,有时候体验就比较糟糕。这个时候实现网络错误请求错误重试也能比较好的解决这种偶发场景。
我们可以使用axios-retry
这个库去实现重拾。用法也非常简单
import axiosRetry from 'axios-retry';
axiosRetry(axios, {});
直接执行axiosRetry
传递axios实例即可。同时它会支持几个配置参数
retries
: 重试次数,默认是3次retryCondition
:一个函数判断发生错误时是否重试。默认是5xx
http 错误或者网络异常或者是幂等请求(GET/HEAD/ OPTIONS/PUT/DELETE)才会重试。shouldResetTimeout
:重试的时候是否重置超时时间。默认不重置。也就是说多次重试请求必须在timeout
内结束retryDelay
每个请求之间的重试延迟时间,默认为0例如,如果我想定制,重试4次、除了默认情况重试外,404也重试、重置超时时间、重试延迟时间50ms,则这样即可
import axiosRetry from 'axios-retry';
axiosRetry(axios, {
retries: 4,
retryCondition: (err) => axiosRetry.isNetworkOrIdempotentRequestError(err) || error.response.status === 404,
shouldResetTimeout: true,
retryDelay: 50
});
axios-retry
实现重试的原理也比较简单
axios-retry
会在axios的config的axios-retry
字段中保存当前已经重试的次数(retryCount
)axios-retry
则在响应拦截器中注册错误处理函数,执行retryCondition
判断是否需要进行重试。如果需要重试则对retryCount
进行++操作,然后返回一个Prommise使用当前的config重新发起一次新的请求new Promise(resolve => setTimeout(() => resolve(axios(config)), delay));
。如果当前不需要重试(retryCondition
返回false
或者已经超过重试次数的场景,直接reject这个错误对象) axios.interceptors.response.use(null, error => {
const config = error.config;
// ....
const currentState = getCurrentState(config);
const shouldRetry = retryCondition(error) && currentState.retryCount < retries;
if (shouldRetry) {
currentState.retryCount += 1;
//.....
return new Promise(resolve => setTimeout(() => resolve(axios(config)), delay));
}
return Promise.reject(error);
});
详细代码在此。还是非常清晰易懂的
在实际场景中,很多时候http请求成功并不说明我们的请求就符合预期的。有以下子几种场景,如果直接使用axios-retry
是无法触发重拾的
{code:1,msg:'some err'}
。有的时候可能是一些偶发错误,这个时候可能也需要重试
{code:0,data:null}
查到返回code:0,data:'some thing'
。这个时候重试也是很重要了。
上文提到axios-retry
的重试原理是通过响应拦截器的错误处理函数去实现的,那么我们在响应拦截器的正常处理函数中抛出这个这个错误是否可以呢?当然是可以的。
axios
的config加一个自定义选项函数判断是否需要重试Promise.reject
抛出一个错误 instance.interceptors.response.use((response) => {
const { data, config, request } = response
if (config?.[namespace]?.shouldRetry?.(data)) {
config[namespace].needRetry = true
return Promise.reject(
createError(
`Axios retry enhance error`,
config,
null,
request,
response
)
)
}
return response
})
axios-retry
的retryCondition
读取到上一步的属性返回true,即可利用axios-retry进行重试 axiosRetry(instance, {
...config,
retryCondition: (error) => {
const {
retryCondition = axiosRetry.isNetworkOrIdempotentRequestError,
} = config
return retryCondition(error) || error.config?.[namespace]?.needRetry
},
})
于是,代码调用的时候只需如下即可
client.get<Result>('http://example.com/test', {
retry: {
// The request will retry when the code isn't 0 even the http code is 200
shouldRetry: (res: Result) => res.code !== 0,
},
})
综合以上讨论,针对axios-retry
进行了二次封装,实现了axios-retry-enhancer。支持axios-retry
原来的参数,并且额外支持上面提到的定义重试逻辑。用法如下即可实现业务优雅重试
import axiosRetryEnhancer from 'axios-retry-enhancer'
import axios from 'axios'
const client = axios.create()
axiosRetryEnhancer(client, {
// same options with axios-retry. See https://github.com/softonic/axios-retry#options
})
interface Result<T = unknown> {
code: number
data: T
}
client.get<Result>('http://example.com/test', {
retry: {
// The request will retry when the code isn't 0 even the http code is 200
shouldRetry: (res: Result) => res.code !== 0,
},
})
码字不易,你的点赞是我最大的动力,嘿嘿