为什么需要重试网络请求
平时写前端或者做小程序开发,经常会遇到接口突然抽风的情况。比如用户点个提交按钮,页面卡一下提示“网络错误”,刷新一下又好了。这种情况大概率不是代码写错了,而是网络抖动导致请求失败。这时候,如果能在代码里自动重试几次,体验就会好很多。
什么情况下该重试
并不是所有失败都要重试。比如返回 400 参数错误,再发十次也没用。但像 502、503 或者直接超时、断网这类问题,多试一两次往往就能成功。特别是移动端用户,网络环境复杂,地铁里、电梯中信号不稳定,适当重试能显著降低报错率。
手动实现一个简单的重试逻辑
最直接的方式是在 fetch 或 axios 这类请求外面包一层重试函数。下面是个用 fetch 配合 Promise 实现的简单例子:
function requestWithRetry(url, options = {}, retries = 3) {
return fetch(url, options)
.then(res => {
if (!res.ok && retries > 0) {
return requestWithRetry(url, options, retries - 1);
}
return res;
})
.catch(err => {
if (retries > 0) {
return requestWithRetry(url, options, retries - 1);
}
throw err;
});
}
这个函数默认最多重试三次,只要失败就递归调用自己,直到成功或次数用完。虽然简单,但在大多数场景下够用了。
加上延迟,避免频繁冲击服务
如果失败后立刻重试,可能服务器还没恢复就被新请求压垮了。更好的做法是加点延迟,比如每次等几百毫秒再试。可以用 setTimeout 包一层:
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function requestWithBackoff(url, options = {}, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const res = await fetch(url, options);
if (res.ok) return res;
} catch (err) {
if (i === retries - 1) throw err;
await delay(2 ** i * 500); // 指数退避
}
}
}
这里用了指数退避策略,第一次等 500ms,第二次 1s,第三次 2s,避免短时间内重复请求。
使用现成工具库更省心
如果项目里请求重试需求多,可以考虑用 axios-retry 或 ky 这类支持重试的库。比如 axios-retry 只需几行代码就能开启:
const axios = require('axios');
const axiosRetry = require('axios-retry');
axiosRetry(axios, { retries: 3 });
axios.get('/api/data').then(res => console.log(res.data));
连错误类型判断都帮你做了,只对网络类错误重试,不影响正常业务逻辑。
别忘了给用户一点反馈
后台自动重试是好事,但如果界面一直卡着不动,用户可能会以为没反应,忍不住狂点。建议在重试期间显示“正在重试”或加载动画,让用户知道系统还在工作。
重试不是万能的
加了重试不代表所有问题都能解决。如果服务器持续崩溃,重试只会增加负担。合理设置最大次数和超时时间,避免无限循环。另外,对于提交订单这类操作,要确保接口幂等,否则可能造成重复下单。