如何优雅地为 Axios 配置失败重试与最大尝试次数

在 Vue 3 中,除了使用自定义的 useRequest 钩子函数外,还可以通过 axios 的拦截器axios-retry 插件实现接口请求失败后的重试逻辑。以下是两种具体方案的实现方式:

方案一:使用 axios 拦截器实现重试

实现步骤: 通过 axios 的响应拦截器捕获错误,并在拦截器内部实现重试逻辑。

1、配置 axios 实例 :在 Vue 项目的入口文件(如 main.js)中配置 axios。

2、添加响应拦截器:在拦截器中捕获错误,并根据条件进行重试。

3、递归重试:在拦截器中控制重试次数和延迟。

javascript 复制代码
// main.js 或单独的 axios 配置文件
import axios from 'axios';

// 配置 axios 实例
const axiosInstance = axios.create({
    baseURL: '/api', // 根路径
    timeout: 10000, // 超时时间
});

// 响应拦截器:处理错误并重试
axiosInstance.interceptors.response.use((response) => response, // 成功响应直接返回
    async (error) => {
		const config = error.config;
		const status = error.response?.status;
		const maxRetries = 5; // 最大重试次数
		const retryDelay = 1000; // 重试间隔(毫秒)

		// 如果没有重试次数或达到最大次数,直接抛出错误
		if (!config || !config._retryCount) {
			config._retryCount = 0;
		}
		
		if (config._retryCount >= maxRetries) {
			return Promise.reject(error);
		}

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

		// 只对特定状态码(如 408、5xx)重试
		if (
			[408, 500, 502, 503, 504].includes(status) ||
			(status === 401 && config.url.includes('/refresh-token')) // 示例:401 时重试刷新 token
		) {
			// 等待一段时间后重试
			await new Promise((resolve) => setTimeout(resolve, retryDelay * config._retryCount));

			// 重新发送请求
			return axiosInstance(config);
		}

		// 其他错误直接抛出
		return Promise.reject(error);
    }
);

// 导出配置好的 axios 实例
export default axiosInstance;

使用示例(在 Vue 组件中)

javascript 复制代码
<template>
	<div>
		<button @click="fetchData">获取数据</button>
		<div v-if="loading">加载中...</div>
		<div v-else-if="data">数据:{{ data }}</div>
		<div v-else-if="error">错误:{{ error.message }}</div>
	</div>
</template>

<script setup>
import axiosInstance from '@/utils/axios'; // 导入配置好的 axios 实例
import { ref } from 'vue';

const loading = ref(false);
const data = ref(null);
const error = ref(null);

const fetchData = async () => {
	try {
		loading.value = true;
		const response = await axiosInstance.get('/data');
		data.value = response.data;
		error.value = null;
	} catch (err) {
		error.value = err;
	} finally {
		loading.value = false;
	}
};
</script>

1、拦截器全局生效 :所有通过 axiosInstance 发起的请求都会经过拦截器,自动处理重试逻辑。可通过配置 config 参数(如 config._retryCount)控制重试次数。

2、重试条件:根据 HTTP 状态码(如 408、5xx)决定是否重试。可扩展为根据业务逻辑(如 token 过期后刷新)触发重试。

3、递归重试 :通过 axiosInstance(config) 重新发送请求,递归调用拦截器。需要手动维护 config._retryCount 来计数。

方案二:使用 axios-retry 插件

通过 axios-retry 插件快速实现重试逻辑,无需手动编写递归逻辑。

1、安装插件

javascript 复制代码
npm install axios-retry

2、配置 axios 实例

javascript 复制代码
// main.js 或单独的 axios 配置文件
import axios from 'axios';
import axiosRetry from 'axios-retry';

const axiosInstance = axios.create({
	baseURL: '/api',
	timeout: 10000,
});

// 配置重试策略
axiosRetry(axiosInstance, {
	retries: 5, // 最大重试次数
	retryDelay: (retryCount) => {
		return retryCount * 1000; // 指数退避:1s、2s、3s...
	},
	retryCondition: (error) => {
		// 自定义重试条件(如针对特定状态码)
		if (error.response) {
			return [408, 500, 502, 503, 504].includes(error.response.status);
		}
		return axiosRetry.isNetworkError(error); // 网络错误自动重试
	},
});

export default axiosInstance;

3、使用示例(与方案一相同)

html 复制代码
<template>
  <!-- 同上 -->
</template>

<script setup>
import axiosInstance from '@/utils/axios'; // 已配置重试的 axios 实例
// 同上
</script>

关键点说明

1、插件优势:开箱即用,代码简洁。支持自定义重试条件、延迟策略(如指数退避)。

内置对网络错误(如超时)的自动重试。

2、灵活性 :可通过 retryCondition 函数灵活控制重试条件。支持 retryDelay 函数实现动态延迟(如指数退避)。


对比与选择

方案 优点 缺点
拦截器手动实现 完全自定义逻辑,无依赖 代码冗余,需手动维护计数器
axios-retry 插件 简单易用,开箱即用 需引入第三方依赖

注意事项

1、避免无限循环 :必须设置最大重试次数(如 maxRetriesretries 参数)。确保重试条件不会无限触发(如 401 未授权 需结合 token 刷新逻辑)。

2、错误类型区分 :对于 4xx 客户端错误 (如 400、401、403),通常不建议重试,需业务逻辑处理(如跳转登录页)。对 5xx 服务端错误(如 500、503)或网络错误(如超时),可安全重试。

3、性能优化 :使用 指数退避 (如 retryDelay: (count) => Math.pow(2, count) * 1000)减少并发重试的压力。结合 限流 (如 maxRetriesretryDelay 组合)避免频繁请求。

相关推荐
天平3 小时前
油猴脚本创建webworker踩坑记录
前端·javascript·typescript
原则猫5 小时前
前端基础大厦
前端
陈随易6 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·后端·程序员
SoaringHeart7 小时前
Flutter进阶:基于 EasyRefresh 的下拉刷新封装 n_easy_refresh_mixin.dart
前端·flutter
IT_陈寒8 小时前
Vite的热更新突然不香了,排查三小时差点砸键盘
前端·人工智能·后端
子兮曰9 小时前
Agency-Agents 深度解析:400+ AI 专家的"梦之队"如何重塑开发工作流
前端·后端·vibecoding
山河木马9 小时前
渲染管线-计算得到gl_Position(顶点着色器)之后续GPU流程
javascript·webgl·图形学
竹林81810 小时前
用 The Graph 查询链上数据实战:从手搓 RPC 到 Subgraph,我的 NFT 项目数据加载快了 10 倍
前端·javascript
妙码生花10 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
Awu122711 小时前
⚡从零开发 Agent CLI(五)实现一个可治理、可扩展的工具系统
前端·人工智能·claude