You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在多请求触发401错误时仅执行一次Axios拦截器?

解决Axios并行401仅刷新一次Token并重试请求的问题

你的代码核心逻辑方向没问题,但缺少对后续请求的等待处理、错误边界覆盖,导致并行场景下无法正确触发重试。以下是修复后的完整实现:

let isRefreshing = false;
let failedQueue = [];

// 统一处理队列中等待的请求
function processQueue(token) {
  failedQueue.forEach(promise => {
    if (token) {
      promise.resolve(token);
    } else {
      promise.reject(new Error('Token刷新失败,请重新登录'));
    }
  });
  failedQueue = [];
}

async function refreshToken() {
  try {
    const response = await normalRoute.post("/users/refresh");
    return response.data.accessToken;
  } catch (refreshError) {
    // 刷新失败时清空队列,避免请求一直挂起
    processQueue(null);
    throw refreshError;
  }
}

privateRoute.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalConfig = error.config;

    // 跳过已重试过的请求,防止无限循环刷新
    if (error.response?.status === 401 && !originalConfig._retry) {
      originalConfig._retry = true;

      if (!isRefreshing) {
        isRefreshing = true;
        try {
          const token = await refreshToken();
          store.dispatch(setAccessToken(token));
          // 更新当前请求的Token并重试
          originalConfig.headers.authorization = `Bearer ${token}`;
          // 批量处理队列中所有等待的请求
          processQueue(token);
          return privateRoute(originalConfig);
        } catch (refreshError) {
          // 刷新失败直接抛出错误,交给前端处理登录跳转
          return Promise.reject(refreshError);
        } finally {
          isRefreshing = false;
        }
      } else {
        // 当前正在刷新Token,将请求加入队列等待结果
        return new Promise((resolve, reject) => {
          failedQueue.push({
            resolve: (newToken) => {
              originalConfig.headers.authorization = `Bearer ${newToken}`;
              resolve(privateRoute(originalConfig));
            },
            reject
          });
        });
      }
    }

    // 非401错误或已重试过的请求,直接抛出错误
    return Promise.reject(error);
  }
);

关键修复点说明

  • 添加重试标记:给请求配置加_retry属性,避免因刷新失败陷入无限循环。
  • 队列Promise化:后续进入的请求会返回Promise,等待Token刷新完成后再执行重试,确保所有并行请求都能获取到新Token。
  • 刷新失败兜底:当refreshToken接口报错时,清空队列并抛出错误,避免请求一直处于等待状态。
  • 完善错误链路:非401场景直接抛出错误,不干扰原有错误处理流程。

结合react-query使用时,保持默认的重试配置即可(默认开启重试),请求被拦截重试后,react-query会自动更新缓存数据。

内容的提问来源于stack exchange,提问作者DevRohan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 12:42:03