前端Axios失败重试

时间:2024-07-07 07:16:24

前端Axios失败重试

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

vite环境变量

# 失败重试次数
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配置中

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页面中接受失败的次数以及是否成功

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

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

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

错误页

<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代码

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;