前端Axios失败重试

前端Axios失败重试

失败重试次数写在vite全局配置中,之后统一修改即可

vite环境变量

properties 复制代码
# 失败重试次数
VITE_BASE_API_RETRY=5

# 失败重试时间
VITE_BASE_API_RETRY_DELAY=3000

Axios重试

思路

  1. 在Axios创建中读取vite环境变量配置,将其赋值
  2. 在发送请求时,如果出错不返回也就是不return之后设置定时器去重试之前的请求
  3. 写在Axios中好处是不用一个一个去配置了
  4. 当重试次数大于约定次数则返回
  5. 如果期间成功了就回到主页

未解决问题

  1. 本来想的是,如果失败了就跳转到失败页这样在失败页中做一些失败的显示,比如重试次数之类显示
  2. 如果使用windows.lcoation方式跳转,在我的谷歌浏览器中会将进行弹窗拦截无法实现跳转,解决无法跳转问题移入vuerouter
  3. 如果请求成功后本来想的是,成功就返回上一次页面,但是会出现页面跳来跳去问题只能让它成功后跳转到固定页面
  4. 因为自定义的配置Axios不支持会报错Vue: Object literal may only specify known properties, and 'retry' does not exist in type 'CreateAxiosDefaults<any>'.

定义Axios变量

在创建请求时将重试次数和时间放入到Axios配置中

ts 复制代码
const request = axios.create({
  // 默认请求地址
  baseURL: import.meta.env.VITE_BASE_API,
  // 设置超时时间
  timeout: import.meta.env.VITE_BASE_API_TIMEOUT,
  retry: import.meta.env.VITE_BASE_API_RETRY, //设置全局重试请求次数(最多重试几次请求)
  retryDelay: import.meta.env.VITE_BASE_API_RETRY_DELAY, //设置全局请求间隔
  // 跨域允许携带凭证
  // withCredentials: true,
});

失败重试

失败的emit

error.config中可以获取到之前在Axios配置中的变量

使用全局总线在/500页面中接受失败的次数以及是否成功

ts 复制代码
async error => {
    const config = error.config;
    // 重试次数
    const retry = config.retry;
    // 重试时间
    const retryDelay = config.retryDelay;
    // 当前重试次数
    config._retryCount = config._retryCount || 0;

    // 如果重试次数大于定义次数返回错误
    if (config._retryCount > retry) {
        return Promise.reject(new Error(error.response.statusText));
    }

    // 失败后打开到500页面
    await router.push('/500');
    mittBus.emit('system-request-error', { retry, retryCount: config._retryCount, isSuccess: false });

    // 设置请求间隔 在发送下一次请求之前停留一段时间,时间为上方设置好的请求间隔时间
    const backoff = new Promise(function (resolve) {
        setTimeout(() => resolve(true), retryDelay || 1000);
    });

    // 如果失败次数加1
    config._retryCount += 1;

    // 再次发送请求
    return backoff.then(() => request(error.config));
}
成功的emit

如果成功使用全局事件总线,在错误页面接受之后跳转

ts 复制代码
(response: any) => {
 // 返回消息内容
  mittBus.emit('system-request-error', { retry: 0, retryCount: 0, isSuccess: true });
  return data;
}

错误页

ts 复制代码
<template>
  <div class="not-container">
   <img alt="500" class="not-img" src="@/assets/images/tip1/500.png" />
   <div class="not-detail">
    <h2>500</h2>
    <h4 v-if="isReTry">抱歉,您的网络不见了~🤦‍♂️🤦‍♀️</h4>
    <h4 v-else class="mt-0 mb-2">您的网络不见了~ 正在重试 {{ retryCount }}/{{ retry }}</h4>
    <button @click="router.push(HOME_URL)">返回首页</button>
   </div>
  </div>
</template>

<script lang="ts" setup>
import { HOME_URL } from '@/enums/constant/route.ts';
import { useRouter } from 'vue-router';
import { onMounted, ref } from 'vue';
import mittBus from '@/utils/mittBus.ts';

const router = useRouter();
const retry = ref(import.meta.env.VITE_BASE_API_RETRY);
const retryCount = ref(0);
const isReTry = ref(false);

/**
 * * 监听失败消息
 */
const onListenSystemRequestError = () => {
  mittBus.on('system-request-error', (value: any) => {
   if (value.isSuccess) {
    router.push('/');
    // router.go(-1);
   }

   retry.value = value.retry;
   retryCount.value = value.retryCount;

   if (parseInt(retry.value) === retryCount.value) {
    isReTry.value = true;
   }
  });
};

onMounted(() => {
  onListenSystemRequestError();
});
</script>

<style lang="scss" scoped>
@import url('index.scss');
</style>

全部Axios代码

ts 复制代码
import { Message } from '@/components/Message/Message.tsx';
import router from '@/router';
import { localGet, localRemove } from '@/utils/util.ts';
import axios from 'axios';
import mittBus from '@/utils/mittBus.ts';

const request = axios.create({
  // 默认请求地址
  baseURL: import.meta.env.VITE_BASE_API,
  // 设置超时时间
  timeout: import.meta.env.VITE_BASE_API_TIMEOUT,
  retry: import.meta.env.VITE_BASE_API_RETRY, //设置全局重试请求次数(最多重试几次请求)
  retryDelay: import.meta.env.VITE_BASE_API_RETRY_DELAY, //设置全局请求间隔
  // 跨域允许携带凭证
  // withCredentials: true,
});

// 请求拦截器
request.interceptors.request.use(config => {
  // 当本地有token表示登录了,请求时将token带上
  const token = localGet('token');

  if (token !== null) {
   config.headers['token'] = token;
  }

  return config;
});

// 响应拦截器
request.interceptors.response.use(
  (response: any) => {
   // 返回相应数据
   const data = response.data;

   // 登录过期
   if (data.code === 208) {
    Message.warning(data.message);
    router.push('/').then();
    localRemove('token');
   }

   // 账户被封禁
   if (data.code === 209) {
    Message.warning(data.message);
    router.push('/').then();
    localRemove('token');
   }

   // 统一处理异常
   if (data.code !== 200 && data.code < 300) {
    Message.warning(data.message);
   } else if (data.code > 300) {
    Message.error(data.message);
   }

   // 返回消息内容
   mittBus.emit('system-request-error', { retry: 0, retryCount: 0, isSuccess: true });
   return data;
  },
  async error => {
   const config = error.config;
   // 重试次数
   const retry = config.retry;
   // 重试时间
   const retryDelay = config.retryDelay;
   // 当前重试次数
   config._retryCount = config._retryCount || 0;

   // 如果重试次数大于定义次数返回错误
   if (config._retryCount > retry) {
    return Promise.reject(new Error(error.response.statusText));
   }

   // 失败后打开到500页面
   await router.push('/500');
   mittBus.emit('system-request-error', { retry, retryCount: config._retryCount, isSuccess: false });

   // 设置请求间隔 在发送下一次请求之前停留一段时间,时间为上方设置好的请求间隔时间
   const backoff = new Promise(function (resolve) {
    setTimeout(() => resolve(true), retryDelay || 1000);
   });

   // 如果失败次数加1
   config._retryCount += 1;

   // 再次发送请求
   return backoff.then(() => request(error.config));
  },
);

export default request;
相关推荐
vivo互联网技术1 分钟前
深度解析悟空系统多机房部署共线改造
前端·npm·多语言·共线改造·多机房
JYeontu1 分钟前
程序员都该掌握的“质因数分解”
前端·javascript·算法
薛定谔的算法2 分钟前
有了HTML、CSS、JS为什么还需要React?
前端·javascript·react.js
方安乐4 分钟前
react之shadcn(一)
前端·react.js·前端框架
阿珊和她的猫6 分钟前
优化过多并发请求的技术策略
前端·javascript·vue.js
阿里云云原生14 分钟前
Agent 越用越聪明?AgentScope Java 在线训练插件来了!
前端·agent
fengci.19 分钟前
ctfshow渔人杯
前端
holeer29 分钟前
【V1.0】Typora 中的 HTML 支持|软件文档自翻译
前端·编辑器·html·typora·web·markdown·文档
敲代码的小吉米30 分钟前
JS两种复制到剪贴板的方法
前端·javascript
NEXT0635 分钟前
React 核心揭秘:虚拟 DOM 原理与 Diff 算法深度解析
前端·react.js·面试