应封装 retryFetch 函数实现重试机制,支持配置 maxRetries、retryDelay 和 shouldRetry,自动处理网络异常与5xx错误,跳过4xx错误,通过 setTimeout + 递归实现非阻塞延迟重试。

在前端用 fetch 实现统一的重试机制,核心不是“拦截”,而是封装一个健壮的请求函数,在失败时自动按策略重试,同时避免重复执行副作用(比如多次提交表单)。关键在于控制重试条件、延迟、次数和中断逻辑。
封装 retryFetch 函数,支持配置化重试
不依赖第三方库,直接封装一个带重试能力的 fetch 替代函数:
- 接受标准
fetch参数(input,init)和重试选项(如maxRetries,retryDelay,shouldRetry) - 对网络异常(如断网)、5xx 响应、超时等可重试错误进行判定,跳过 4xx(如 401、404)等语义明确不可重试的情况
- 使用
setTimeout+ 递归或循环实现延迟重试,避免阻塞主线程
示例代码:
function retryFetch(input, init = {}, options = {}) {
const {
maxRetries = 3,
retryDelay = 1000,
shouldRetry = (err, res) =>
err instanceof TypeError || // 网络错误(如 Failed to fetch)
(res && res.status >= 500 && res.status < 600) // 5xx 服务端错误
} = options;
<p>return fetch(input, init)
.then(res => {
if (!res.ok && shouldRetry(null, res)) {
throw new Error(<code>HTTP ${res.status}</code>);
}
return res;
})
.catch(err => {
if (maxRetries <= 0) throw err;
return new Promise(resolve => {
setTimeout(() => {
resolve(
retryFetch(input, init, {
...options,
maxRetries: maxRetries - 1,
retryDelay: Math.min(retryDelay * 2, 10000) // 指数退避,上限 10s
})
);
}, retryDelay);
});
});
}</p>全局统一调用,替代原生 fetch
将 retryFetch 挂载到全局或通过模块导出,在业务中统一使用它发起请求,避免各处重复写重试逻辑:
立即学习“Java免费学习笔记(深入)”;
- 所有 API 调用都走这个函数,例如:
retryFetch('/api/user', { method: 'POST' }) - 可配合 AbortController 实现手动取消(如页面卸载、用户切换),防止重试在无效上下文中继续执行
- 对登录态失效(401)等需特殊处理的错误,可在
shouldRetry中排除,交由上层统一跳转登录页
结合请求上下文做智能判断(如只对 GET 请求重试)
并非所有请求都适合重试。幂等性是关键依据:
- 推荐重试:GET、HEAD、OPTIONS 等只读请求,天然幂等
- :POST、PUT、DELETE 等写操作,除非后端明确支持幂等(如带 Idempotency-Key)
- 可在
shouldRetry中检查init.method,例如:method === 'GET'
错误聚合与可观测性(可选增强)
便于排查问题,可在重试过程中收集日志或上报:
- 每次重试前打印日志:
console.warn(`[retryFetch] Attempt #${4 - maxRetries} for ${input}`) - 最终失败时,抛出包含原始错误、重试次数、响应状态的结构化错误对象
- 与 Sentry 或自建监控系统集成,标记“重试后成功”或“重试耗尽”事件


















