JavaScript 中 fetch 无内置重试机制,需封装 retryFetch 函数实现白名单重试:仅对匹配 URL 模式、指定状态码(如 502/503/504/0)及幂等方法(GET/HEAD)的请求重试,支持指数退避与最大重试次数限制。

在 JavaScript 中,fetch 本身不提供重试机制,但可以通过封装一个带白名单匹配和自动重试逻辑的函数来实现:只对特定错误状态(如 502、503、504)或特定 URL 模式失败的请求进行重试,其他错误(如 401、404)直接拒绝。
一、定义可重试的白名单条件
白名单不是指“允许调用的接口列表”,而是指“满足哪些条件时才允许重试”。常见维度包括:
-
HTTP 状态码:如
502、503、504、0(网络中断,fetch 可能抛异常或返回 status 0) -
URL 匹配规则:用正则或字符串前缀限定仅对某些接口启用重试,例如
/api/v2/或https://svc.example.com/ -
请求方法:通常只对
GET和HEAD这类幂等请求重试,避免重复提交 POST/PUT
二、封装带白名单的 retryFetch 函数
以下是一个轻量、可配置的实现(支持最大重试次数、延迟递增、白名单判断):
示例代码(ES6+,无依赖):
立即学习“Java免费学习笔记(深入)”;
function retryFetch(input, init = {}, options = {}) {
const {
retryCount = 3,
baseDelay = 500,
whitelistUrls = [/^https?:\/\/[^/]+\/api\//i], // 默认匹配 /api/ 路径
whitelistStatuses = [0, 502, 503, 504],
whitelistMethods = ['GET', 'HEAD']
} = options;
<p>const url = typeof input === 'string' ? input : input.url || '';
const method = (init.method || 'GET').toUpperCase();</p><p>// 判断是否命中白名单:URL + 方法 + (后续判断状态)
const isWhitelistedUrl = whitelistUrls.some(pattern => pattern.test(url));
const isWhitelistedMethod = whitelistMethods.includes(method);
const shouldRetryByDefault = isWhitelistedUrl && isWhitelistedMethod;</p><p>const attempt = async (n) => {
try {
const res = await fetch(input, init);
// 成功响应,或虽失败但不在白名单状态中 → 不重试
if (res.ok || !whitelistStatuses.includes(res.status)) {
return res;
}
// 白名单状态且未达重试上限 → 延迟后重试
if (n < retryCount) {
await new Promise(r => setTimeout(r, baseDelay <em> Math.pow(2, n)));
return attempt(n + 1);
}
return res; // 达到上限,返回最后一次响应
} catch (err) {
// 网络异常(如 TypeError: Failed to fetch)、DNS 失败等,status 为 0
if (shouldRetryByDefault && n < retryCount) {
await new Promise(r => setTimeout(r, baseDelay </em> Math.pow(2, n)));
return attempt(n + 1);
}
throw err;
}
};</p><p>return attempt(0);
}三、使用示例与注意事项
基本调用:
retryFetch('/api/data', { method: 'GET' })
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error('最终失败:', err));自定义白名单(只对某个服务重试):
retryFetch('/api/payment/status', {}, {
whitelistUrls: [/^https:\/\/pay\.example\.com\//],
retryCount: 2
});关键提醒:
- 不要对
POST/PUT/DELETE默认开启重试,除非业务确认幂等(例如带唯一 request-id 的接口) - 服务端需配合支持幂等性,否则重试可能造成重复下单、扣款等问题
- 避免无限重试:务必设置
retryCount上限,并建议搭配指数退避(代码中已实现) - 注意 CORS 和 redirect 行为:fetch 默认不带 cookie,重试时保持 init 一致
四、进阶建议(可选)
如需更健壮能力,可考虑:
- 添加 abortController 支持取消重试链
- 将重试日志上报监控系统(如记录重试次数、耗时、最终状态)
- 结合缓存策略:对 GET 请求,首次失败后从 Cache API 或内存缓存 fallback
- 用 AbortSignal.timeout()(Chrome 109+)限制单次 fetch 超时,避免卡死


















