← 中文资源

简体中文版本

Axios 拦截器指数退避重试

通过 Axios 响应拦截器实现自动重试:仅对幂等方法与瞬态状态码生效,按指数退避递增延迟并限制总尝试次数。

阅读英文原文

示例说明

重试最容易踩的坑是对非幂等请求自动重试造成重复扣款。这个拦截器把幂等性判断显式写进重试条件:只有 GET、HEAD、PUT、DELETE 这类可安全重复的方法,且响应属于限流或网关瞬态错误时才重试。attempt 计数挂在 config 上随请求对象流转,避免外部状态。

技术要点

  • 幂等方法白名单是重试的前置门槛
  • 瞬态状态码白名单隔离业务错误
  • 2 的次幂乘基数生成递增退避

代码解读

拦截器的错误分支从 error.config 取回请求配置;__retries 字段初始化为 0,每次重试自增并计算 1 秒、2 秒、4 秒递增的延迟。任何条件不满足都直接 reject 保留原始错误语义。重试调用 client(config) 会重新走完整的请求链,包括其他拦截器。

使用建议

若服务端支持 Idempotency-Key,非幂等方法也可以安全重试。429 响应应优先读取 Retry-After 头而不是固定退避。重试日志要带尝试序号,避免排障时误判为多次独立失败。

代码示例

import axios from 'axios';

const client = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 8000,
  headers: { 'x-client': 'batch-sync/1.2' },
});

client.interceptors.response.use(
  (res) => res,
  async (error) => {
    const config = error.config ?? {};
    const retries = config.__retries ?? 0;
    const idempotent = ['GET', 'HEAD', 'PUT', 'DELETE'].includes(config.method);

    const transient = error.response
      && [429, 502, 503, 504].includes(error.response.status);

    if (!idempotent || !transient || retries >= 3) {
      return Promise.reject(error);
    }

    config.__retries = retries + 1;
    const delay = 2 ** config.__retries * 500;
    await new Promise((r) => setTimeout(r, delay));
    return client(config);
  },
);

const data = await client.get('/catalog?page=2');
console.log('items:', data.data.items.length);