1. 首页

77.9K Star 的 Axios 项目如何优雅实现请求重试

axios是什么,无需多讲,axios解析的可以看下77.9K Star 的 Axios 项目有哪些值得借鉴的地方这篇文章

为什么需要请求重试

项目中,经常会有很多用户的网络抽风或者各种原因造成偶发性的网络异常请求错误,如果没有重试机制,有时候体验就比较糟糕。这个时候实现网络错误请求错误重试也能比较好的解决这种偶发场景。

如何去做呢

我们可以使用axios-retry这个库去实现重拾。用法也非常简单

 js
import axiosRetry from 'axios-retry';
axiosRetry(axios, {});
/* 给大家推荐一个面试刷题:Js中文网 - 全球前端挚爱的技术成长平台 https://www.javascriptc.com/special/leetcode */

直接执行axiosRetry传递axios实例即可。同时它会支持几个配置参数

  • retries: 重试次数,默认是3次
  • retryCondition:一个函数判断发生错误时是否重试。默认是5xxhttp 错误或者网络异常或者是幂等请求(GET/HEAD/ OPTIONS/PUT/DELETE)才会重试。
  • shouldResetTimeout:重试的时候是否重置超时时间。默认不重置。也就是说多次重试请求必须在timeout内结束
  • retryDelay每个请求之间的重试延迟时间,默认为0

例如,如果我想定制,重试4次、除了默认情况重试外,404也重试、重置超时时间、重试延迟时间50ms,则这样即可

 js
import axiosRetry from 'axios-retry';
axiosRetry(axios, {
    retries: 4,
    retryCondition: (err) => axiosRetry.isNetworkOrIdempotentRequestError(err) || error.response.status === 404,
    shouldResetTimeout: true,
    retryDelay: 50
});
/* 给大家推荐一个面试刷题:Js中文网 - 全球前端挚爱的技术成长平台 https://www.javascriptc.com/special/leetcode */

实现原理

axios-retry实现重试的原理也比较简单

  • axios-retry会在axios的config的axios-retry字段中保存当前已经重试的次数(retryCount)
  • axios会在http异常/网络异常的情况下抛出错误。axios-retry则在响应拦截器中注册错误处理函数,执行retryCondition判断是否需要进行重试。如果需要重试则对retryCount进行++操作,然后返回一个Prommise使用当前的config重新发起一次新的请求new Promise(resolve => setTimeout(() => resolve(axios(config)), delay));。如果当前不需要重试(retryCondition返回false或者已经超过重试次数的场景,直接reject这个错误对象)
 js
  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);
  });
/* 给大家推荐一个面试刷题:Js中文网 - 全球前端挚爱的技术成长平台 https://www.javascriptc.com/special/leetcode */

详细代码在此。还是非常清晰易懂的

更进一步

在实际场景中,很多时候http请求成功并不说明我们的请求就符合预期的。有以下子几种场景,如果直接使用axios-retry是无法触发重拾的

  • 业务code异常

以笔者实际项目为例,后端返回异常时,http code为200,但是返回code非0的错误,如{code:1,msg:'some err'}。有的时候可能是一些偶发错误,这个时候可能也需要重试

  • 异步接口返回不符合预期

假设以下场景。首先操作a先上传了视频;紧接这b操作去查询这个视频的信息,可能刚上传完,后端一些信息落db的时候有延迟。偶发的我们马上查询的时候可能查不到这个信息,需要延迟个几ms才能查到。例如查不到返回{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-retryretryCondition读取到上一步的属性返回true,即可利用axios-retry进行重试
 js
  axiosRetry(instance, {
    ...config,
    retryCondition: (error) => {
      const {
        retryCondition = axiosRetry.isNetworkOrIdempotentRequestError,
      } = config
      return retryCondition(error) || error.config?.[namespace]?.needRetry
    },
  })
/* 给大家推荐一个面试刷题:Js中文网 - 全球前端挚爱的技术成长平台 https://www.javascriptc.com/special/leetcode */

于是,代码调用的时候只需如下即可

 js
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,
  },
})
/* 给大家推荐一个面试刷题:Js中文网 - 全球前端挚爱的技术成长平台 https://www.javascriptc.com/special/leetcode */

封装

综合以上讨论,针对axios-retry进行了二次封装,实现了axios-retry-enhancer。支持axios-retry原来的参数,并且额外支持上面提到的定义重试逻辑。用法如下即可实现业务优雅重试

 js
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,
  },
})
/* 给大家推荐一个面试刷题:Js中文网 - 全球前端挚爱的技术成长平台 https://www.javascriptc.com/special/leetcode */

码字不易,你的点赞是我最大的动力,嘿嘿

作者:flytam
链接:https://juejin.im/post/6895702603003330573

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

本文著作权归作者所有,如若转载,请注明出处

转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com

标题:77.9K Star 的 Axios 项目如何优雅实现请求重试

链接:https://www.javascriptc.com/4766.html

« Mysql中这21个写SQL的好习惯,你不能不会哦
前端如何搞定数据结构与算法(先导篇)»
Flutter 中文教程资源

相关推荐

QR code