在 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 应用的健壮性和用户体验。请记住,根据你的具体需求调整重试次数、退避延迟和重试条件。