在网络不稳定的场景下,超时请求重传 是提升应用健壮性的关键策略。以下是前端实现请求超时重试的完整方案,涵盖 Axios 和 Fetch API 两种主流方式,帮你轻松应对网络波动!
核心实现方案
1. 基于 Axios 实现(推荐)
Axios 提供了拦截器(interceptors)和配置项,非常适合实现超时重传。
完整代码示例
typescript
import axios, { AxiosRequestConfig, AxiosError } from 'axios';
// 重试配置
const RETRY_COUNT = 3; // 最大重试次数
const RETRY_DELAY = 1000; // 重试延迟(ms)
const TIMEOUT = 5000; // 单次请求超时时间(ms)
// 创建 Axios 实例
const http = axios.create({ timeout: TIMEOUT });
// 请求拦截器:记录重试次数
http.interceptors.request.use((config: any) => {
config.__retryCount = config.__retryCount || 0;
return config;
});
// 响应拦截器:错误处理与重试
http.interceptors.response.use(null, async (error: AxiosError) => {
const config = error.config;
// 如果不是超时错误或达到重试上限,直接拒绝
if (
error.code !== 'ECONNABORTED' ||
config.__retryCount >= RETRY_COUNT
) {
return Promise.reject(error);
}
// 增加重试计数
config.__retryCount += 1;
// 延迟重试
await new Promise(resolve =>
setTimeout(resolve, RETRY_DELAY)
);
return http(config);
});
// 使用示例
http.get('/api/data')
.then(response => console.log(response.data))
.catch(error => console.error('最终失败:', error));
关键点说明
- 错误类型判断 :只重试超时错误(
ECONNABORTED
) - 重试控制 :通过
__retryCount
记录已重试次数 - 延迟重试:避免立即重试导致服务器压力骤增
2. 基于 Fetch API 实现
Fetch API 需要手动封装重试逻辑,适合原生场景。
完整代码示例
typescript
const fetchWithRetry = async (
url: string,
options: RequestInit = {},
retries: number = 3,
delay: number = 1000
): Promise<Response> => {
try {
// 添加超时控制
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
const response = await fetch(url, {
...options,
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response;
} catch (error) {
if (retries <= 0) throw error;
await new Promise(resolve => setTimeout(resolve, delay));
return fetchWithRetry(url, options, retries - 1, delay);
}
};
// 使用示例
fetchWithRetry('/api/data')
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error('最终失败:', err));
关键点说明
- 超时控制 :通过
AbortController
实现 - 递归重试:通过递归调用实现次数控制
- 错误边界:区分网络错误和业务错误(HTTP状态码)
高级优化策略
1. 指数退避算法
重试间隔随时间指数增长,避免雪崩效应:
arduino
const delay = Math.pow(2, retries) * 1000; // 2^n秒
2. 关键请求标记
对支付等关键请求启用重试,对普通查询请求禁用:
arduino
if (config.isCritical) {
// 执行重试逻辑
}
3. 用户提示优化
- 首次失败显示"正在重试..."
- 最终失败显示"网络不稳定,请手动重试"
各方案对比
方案 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
Axios | 拦截器机制完善 | 需要封装 | 已有Axios的项目 |
Fetch | 浏览器原生支持 | 手动实现复杂 | 追求轻量的项目 |
React Query | 内置重试机制 | 需要引入额外库 | React生态 |
总结
- Axios 方案:通过拦截器优雅实现,适合大多数项目
- Fetch 方案:更底层控制,适合特殊需求场景
- 优化策略:指数退避 + 智能提示提升用户体验