请求失败后如何优雅地重试三次?

程序猿胜楠 阅读 32

我在用 fetch 做 API 请求,网络偶尔不稳定,想加个重试机制,但不知道怎么写才不乱。试过在 catch 里再调一次,结果有时候会无限重试,或者状态没控制好。

比如下面这个简单的请求组件,该怎么加最多重试三次的逻辑?

<script>
async function fetchData() {
  const res = await fetch('/api/data');
  if (!res.ok) throw new Error('请求失败');
  return res.json();
}
</script>
我来解答 赞 11 收藏
二维码
手机扫码查看
2 条解答
 ___晨曦
这个问题的关键是把重试次数控制住,别让它跑飞了。下面是个常见的写法:

async function fetchWithRetry(url, options = {}, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const res = await fetch(url, options);
// 4xx 错误通常重试也没用,直接抛掉
if (!res.ok) {
if (res.status >= 400 && res.status < 500) {
throw new Error(客户端错误: ${res.status});
}
throw new Error(请求失败: ${res.status});
}
return await res.json();
} catch (error) {
// 最后一次尝试失败了就直接抛异常
if (i === maxRetries - 1) throw error;
// 指数退避:1s, 2s, 4s...别马上重试
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
}
}
}


用起来就是这样:

async function fetchData() {
return await fetchWithRetry('/api/data');
}


几个安全上的坑得提醒你:

不是所有请求都能随便重试。如果是 POST、PUT 这种会修改数据的请求,重试可能导致重复操作。比如用户付款,重试两次就付三次钱的事儿不是没发生过。解决办法是后端保证幂等性,或者前端生成个唯一请求 ID 让后端去重。

退避策略很重要。别傻傻地马上重试,网络抖动的时候你越重试越堵。上面的指数退避(1秒、2秒、4秒)是基础玩法,生产环境可以加随机抖动(jitter)避免多请求同时涌入。

4xx 错误别重试。客户端的请求有问题(比如 401 未认证、400 参数错误),重试一百万次也是白搭,反而可能把接口打挂。上面的代码已经帮你过滤掉了 400-499 的错误。

如果你的场景是用户登录这种关键操作,建议还是用专门的库比如 axios-retry 或者 workbox,边界情况处理得更完善。自己写的话上面这个够用,但记得根据实际业务调整策略。
点赞
2026-03-12 10:05
文鑫的笔记
最简单的办法,给fetchData加个retry参数,在catch里递归调用直到次数用完:

async function fetchData(retry = 3) {
try {
const res = await fetch('/api/data');
if (!res.ok) throw new Error('请求失败');
return res.json();
} catch (err) {
if (retry <= 0) throw err;
console.log(重试剩余 ${retry} 次);
return fetchData(retry - 1);
}
}


调用的时候不用传参数,默认就试3次。试完还不行就抛出错误,外面再catch处理。
点赞 4
2026-03-05 23:04