记一次重试机制和服务器响应慢导致的异常

发布时间 2023-08-18 17:13:24作者: 鲲逸鹏

先说下异常是什么:正常情况下,我们的数据,axios返回后都是在res.data中的,于是项目里面常见的就是来个响应拦截,然后返回res.data。

现在重试机制 + 服务器响应慢,会导致最后返回的数据直接就是res.data里面的内容了,你再.data,自然就有问题了

解决:判断是否是axiosResponse对象,如果是,正常返回res.data,如果不是,直接返回res(现阶段:重试的请求得到的结果和之前超时请求的结果一样的)

过程分析:

1.正常请求

先看下正常请求的日志输出:res是axiosResponse对象

------------------------
request AOP 1692346964543 {transitional: {…}, adapter: Array(2), transformRequest: Array(1), transformResponse: Array(1), timeout: 5000, …}
Response AOP res: {data: {…}, status: 200, statusText: 'OK', headers: AxiosHeaders, config: {…}, …}
Response AOP HttpStatus: 200 | JDStatus 200
------------------------
weightVolumeUpload {barCode: 'JD11', code: 200, message: 'OK'}

正常

2.请求超时

再请求一次的时候超时了(服务器响应慢)触发了重试机制

------------------------
request AOP 1692346973680 {transitional: {…}, adapter: Array(2), transformRequest: Array(1), transformResponse: Array(1), timeout: 5000, …}
retry touch: AxiosError {message: 'timeout of 5000ms exceeded', name: 'AxiosError', code: 'ECONNABORTED', config: {…}, request: XMLHttpRequest, …}
retryCount: 1

3.过多响应

然后服务器又很快反应了,还把上次超时的数据也给我返回了。。。

------------------------
request AOP 1692346980593 {transitional: {…}, adapter: Array(2), transformRequest: Array(1), transformResponse: Array(1), timeout: 5000, …}
Response AOP res: {data: {…}, status: 200, statusText: 'OK', headers: AxiosHeaders, config: {…}, …}
Response AOP HttpStatus: 200 | JDStatus 200
------------------------
Response AOP res: {barCode: 'JD11', code: 200, message: 'OK'}
Response AOP HttpStatus: undefined | JDStatus undefined
------------------------

4.响应处理

但是,Ajax的地方,只收到服务器返回的最后一次数据。类型不是axiosResponse的,而是直接就是服务器返回的数据:

weightVolumeUpload {barCode: 'JD11', code: 200, message: 'OK'}

过程如图所示:

axios请求得到的数据一般都会放在res.data里面,响应拦截一般会返回一个res.data,现在我们可能会遇到直接返回data的情况,我是这样暂时处理的:(这两次服务器返回结果其实一样

每个AxiosResponse对象都会有个res.status属性,服务器端返回的数据没有这个属性名字是code(你后端返回也有个status就不能这么判断,可以通过实例对象判断,也可以通过其他属性判断)

5.附录

// 响应拦截
myAxios.interceptors.response.use(res => {
    console.debug("Response AOP res:", res);
    console.debug("Response AOP HttpStatus:", res?.status, '| JDStatus', res?.data?.code);
    console.debug("------------------------");
    // 是AxiosResponse对象才是我要的东西
    if (res.hasOwnProperty('status')) { // 这个逻辑你要根据你后端返回微调
        return res.data;
    } else {
        return res; // 返回对象不是AxiosResponse,这个res就相当于是res.data里面的数据了
    }
}, error => {
    return Promise.reject(error);
})

重试机制:

axiosRetry(myAxios, {
    retries: 3, // 重试次数  
    retryDelay: (retryCount) => {
        console.debug('retryCount:', retryCount);
        return retryCount * 1000; // 重试时间累加,可以写1500
    },
    shouldResetTimeout: true, // 每次重试都重置超时时间
    // 自定义条件,针对状态为500、1000、超时、网络问题进行重试
    retryCondition: (error) => {
        console.debug('retry touch:', error);
        return error?.response?.status === 500 || // JD服务器内部错误
            error?.response?.status === 1000 || // JD服务器内部错误
            error?.code === 'ECONNABORTED' || // 后端响应超时☆
            error?.code == 'ERR_NETWORK'; // 网络异常
    },
});

重试机制