HOOOS

Vue 3 + Axios:使用指数退避实现自动重试机制

0 1 RobustDev Vue 3Axios自动重试指数退避
Apple

在 Vue 3 项目中,使用 Axios 发送 API 请求时,网络不稳定或者服务器偶发性错误可能导致请求失败。为了提高应用的健壮性,我们可以实现一个自动重试机制,当请求失败时自动重试,并且使用指数退避策略,即每次重试的间隔时间逐渐增加。下面是如何实现的详细步骤和代码示例:

1. 安装 Axios (如果尚未安装)

首先,确保你的 Vue 3 项目已经安装了 Axios。如果没有,可以使用 npm 或者 yarn 安装:

npm install axios
# 或者
yarn add axios

2. 创建 Axios 实例并配置拦截器

创建一个 Axios 实例,并配置请求和响应拦截器。响应拦截器用于检测请求是否失败,并根据情况进行重试。

// axios.config.js
import axios from 'axios';

const axiosInstance = axios.create({
  baseURL: '/api', // 你的 API 基础 URL
  timeout: 10000, // 请求超时时间,单位毫秒
});

// 定义最大重试次数和退避延迟
const MAX_RETRIES = 3;
const BACKOFF_DELAY = 1000; // 初始退避延迟,单位毫秒

axiosInstance.interceptors.response.use(
  (response) => {
    // 请求成功,直接返回响应数据
    return response;
  },
  (error) => {
    // 请求失败,进行重试逻辑
    const config = error.config;

    // 如果 config 不存在,或者 retry 选项被显式设置为 false,则不重试
    if (!config || config.retry === false) {
      return Promise.reject(error);
    }

    // 设置重试次数,默认为 0
    config.__retryCount = config.__retryCount || 0;

    // 如果重试次数超过最大重试次数,则不重试
    if (config.__retryCount >= MAX_RETRIES) {
      return Promise.reject(error);
    }

    // 增加重试次数
    config.__retryCount += 1;

    // 计算退避延迟
    const backoff = BACKOFF_DELAY * Math.pow(2, config.__retryCount - 1);

    // 使用 Promise 进行延迟重试
    return new Promise((resolve) => {
      setTimeout(() => {
        console.log(`Retrying request to ${config.url}, retry count: ${config.__retryCount}`);
        resolve(axiosInstance(config));
      }, backoff);
    });
  }
);

export default axiosInstance;

代码解释:

  • axiosInstance: 创建一个 Axios 实例,可以设置基础 URL 和超时时间等配置。
  • MAX_RETRIES: 定义最大重试次数。
  • BACKOFF_DELAY: 定义初始退避延迟时间(毫秒)。
  • axiosInstance.interceptors.response.use: 配置响应拦截器,用于处理响应和错误。
  • error.config: Axios 错误对象中的 config 属性包含了原始请求的配置信息。
  • config.__retryCount: 自定义属性,用于记录重试次数。
  • backoff: 计算退避延迟时间,使用指数退避策略:BACKOFF_DELAY * Math.pow(2, config.__retryCount - 1)
  • setTimeout: 使用 setTimeout 函数进行延迟重试。

3. 在 Vue 组件中使用 Axios 实例

在 Vue 组件中引入 Axios 实例,并发送 API 请求。

// MyComponent.vue
<template>
  <div>
    <button @click="fetchData">获取数据</button>
    <p v-if="data">{{ data }}</p>
    <p v-if="error">Error: {{ error.message }}</p>
  </div>
</template>

<script>
import axiosInstance from './axios.config';
import { ref } from 'vue';

export default {
  setup() {
    const data = ref(null);
    const error = ref(null);

    const fetchData = async () => {
      try {
        const response = await axiosInstance.get('/data'); // 替换为你的 API 接口
        data.value = response.data;
        error.value = null;
      } catch (e) {
        error.value = e;
        data.value = null;
        console.error('Failed to fetch data:', e);
      }
    };

    return {
      data,
      error,
      fetchData,
    };
  },
};
</script>

代码解释:

  • import axiosInstance from './axios.config': 引入配置好的 Axios 实例。
  • axiosInstance.get('/data'): 使用 Axios 实例发送 GET 请求,/data 替换为你的 API 接口地址。
  • try...catch: 使用 try...catch 块捕获请求错误。

4. 测试重试机制

为了测试重试机制,你可以模拟 API 请求失败的情况。例如,可以临时关闭服务器,或者在服务器端设置一个间歇性返回错误的接口。

5. 可选配置

  • 自定义重试条件: 你可以根据实际需求,自定义重试条件。例如,只对特定状态码(如 500、502、503)的错误进行重试。
  • 取消重试: 在某些情况下,你可能需要取消重试。例如,当用户取消操作时,或者当错误类型表明重试没有意义时(如 400 错误)。你可以在 error.config 中设置一个标志来控制是否重试。
  • 添加 Loading 状态: 在重试期间,可以显示 Loading 状态,提升用户体验。

完整示例

下面是一个完整的示例,包括 Axios 配置文件和 Vue 组件:

axios.config.js:

import axios from 'axios';

const axiosInstance = axios.create({
  baseURL: '/api', // 你的 API 基础 URL
  timeout: 10000, // 请求超时时间,单位毫秒
});

const MAX_RETRIES = 3;
const BACKOFF_DELAY = 1000;

axiosInstance.interceptors.response.use(
  (response) => {
    return response;
  },
  (error) => {
    const config = error.config;

    if (!config || config.retry === false) {
      return Promise.reject(error);
    }

    config.__retryCount = config.__retryCount || 0;

    if (config.__retryCount >= MAX_RETRIES) {
      return Promise.reject(error);
    }

    config.__retryCount += 1;

    const backoff = BACKOFF_DELAY * Math.pow(2, config.__retryCount - 1);

    return new Promise((resolve) => {
      setTimeout(() => {
        console.log(`Retrying request to ${config.url}, retry count: ${config.__retryCount}`);
        resolve(axiosInstance(config));
      }, backoff);
    });
  }
);

export default axiosInstance;

MyComponent.vue:

<template>
  <div>
    <button @click="fetchData" :disabled="loading">{{ loading ? 'Loading...' : '获取数据' }}</button>
    <p v-if="data">{{ data }}</p>
    <p v-if="error">Error: {{ error.message }}</p>
  </div>
</template>

<script>
import axiosInstance from './axios.config';
import { ref } from 'vue';

export default {
  setup() {
    const data = ref(null);
    const error = ref(null);
    const loading = ref(false);

    const fetchData = async () => {
      loading.value = true;
      error.value = null;
      try {
        const response = await axiosInstance.get('/data');
        data.value = response.data;
      } catch (e) {
        error.value = e;
        data.value = null;
        console.error('Failed to fetch data:', e);
      } finally {
        loading.value = false;
      }
    };

    return {
      data,
      error,
      loading,
      fetchData,
    };
  },
};
</script>

总结

通过配置 Axios 拦截器,我们可以轻松地实现自动重试机制,并使用指数退避策略来避免对服务器造成过大的压力。这种方法可以有效地提高 Vue 3 应用的健壮性和用户体验。请记住,根据你的具体需求调整重试次数、退避延迟和重试条件。

点评评价

captcha
健康