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

React中使用axios-auth-refresh实现刷新令牌时部分API在401场景下不重试的问题求助

问题排查与解决方案

我仔细看了你的代码和问题描述,发现几个关键问题导致fetchUsers返回401时不触发重试,下面一步步拆解原因和修复方案:

1. 最直接的错误:Axios请求参数传递格式错误

Axios的get方法只接受两个参数:url和config(可选),所有配置(包括params、validateStatus)都要放在同一个config对象里。你现在的写法把params和validateStatus分开传递,导致validateStatus根本没被Axios识别,请求的错误处理逻辑不符合预期。

修复后的fetchUsers:

const fetchUsers = async () => {
  try {
    const { data } = await api.get(`users/`, {
      params: { tripUsers: true },
      validateStatus: (status) => status !== 401 && status !== 403
    })
    setUsers(data);
  } catch (err) {
    console.error("获取用户列表失败:", err);
  }
}

修复后的fetchProfile(同样修正参数格式):

const fetchProfile = async () => {
  try {
    const { data } = await api.get(`/users/${user.userId}`, {
      validateStatus: (status) => status !== 401 && status !== 403
    })
    const {statusCode, message} = data;
    console.log(data);
    if(!statusCode) {
      setState(data);
    }
  } catch (err) {
    console.error("获取用户信息失败:", err);
  }
}

2. Refresh逻辑的错误处理依赖错误

你的refreshAuthLogic里判断token是否无效,依赖的是返回数据中的statusCode,而不是Axios响应的实际状态码。如果后端直接返回401/403状态码,而数据里没有statusCode字段,这段判断就会失效,导致后续逻辑出错,无法触发重试。

修复后的refreshAuthLogic:

const refreshAuthLogic = async (failedRequest) => {
  const refresh_token = Cookies.get(REFRESH_TOKEN_COOKIE_NAME);
  if (!refresh_token) {
    // 没有刷新令牌,直接拒绝,不重试
    return Promise.reject(new Error("无可用刷新令牌"));
  }

  try {
    const tokenRefreshResponse = await api.post('auth/createtoken', {}, {
      headers: {'Authorization': 'Bearer ' + refresh_token},
      // 只接受成功或明确的错误状态码,不用强制所有状态都视为成功
      validateStatus: (status) => status === 200 || status === 401 || status === 403
    });

    // 用响应状态码判断是否失效,更可靠
    if (tokenRefreshResponse.status === 401 || tokenRefreshResponse.status === 403) {
      Cookies.remove(REFRESH_TOKEN_COOKIE_NAME);
      if (!window.location.href.includes('login')) {
        window.location.href = "http://localhost:3000/login";
      }
      return Promise.reject(new Error("刷新令牌无效"));
    }

    const access_token = tokenRefreshResponse.data.access_token;
    if (!access_token) throw new Error("未返回新的访问令牌");

    Cookies.set(TOKEN_COOKIE_NAME, access_token, { expires: 60 })
    api.defaults.headers.Authorization = `Bearer ${access_token}`;
    failedRequest.response.config.headers['Authorization'] = `Bearer ${access_token}`;
    
    // 返回成功Promise,告诉axios-auth-refresh可以重试请求
    return Promise.resolve();
  } catch (err) {
    // 处理网络错误或其他异常
    Cookies.remove(REFRESH_TOKEN_COOKIE_NAME);
    if (!window.location.href.includes('login')) {
      window.location.href = "http://localhost:3000/login";
    }
    return Promise.reject(err);
  }
}

3. 缺失初始Authorization头初始化

页面刷新后,你的Axios实例默认没有从Cookie中读取已有的访问令牌,导致第一次请求(比如fetchUsers)没有携带Authorization头,后端返回401时,刷新逻辑的触发可能出现异常。

在api.js中添加初始化逻辑:

const api = Axios.create({
  baseURL: process.env.REACT_APP_BACKEND_URL,
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  }
});

// 新增:初始化Authorization头
const initialAccessToken = Cookies.get(TOKEN_COOKIE_NAME);
if (initialAccessToken) {
  api.defaults.headers.Authorization = `Bearer ${initialAccessToken}`;
}

// 后续的refresh拦截器代码不变...

4. 可选:添加拦截器调试配置

可以给axios-auth-refresh添加调试选项,方便排查重试触发情况:

createAuthRefreshInterceptor(api, refreshAuthLogic, {
  statusCodes: [401, 403], // 指定触发刷新的状态码
  onRetry: (request) => {
    console.log("正在重试请求:", request.url);
  }
});

为什么fetchProfile之前能正常触发?

因为fetchProfile的第二个参数是空对象,Axios把它当成了config,第三个参数的validateStatus被忽略了,请求用了默认的错误处理逻辑(401视为错误),所以触发了刷新拦截器。而fetchUsers的参数格式错误,但因为是页面加载后的第一个请求,没有初始Authorization头,加上刷新逻辑的判断问题,导致重试未触发。

按照上面的步骤修复后,fetchUsers返回401时应该能正常触发令牌刷新和请求重试了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 08:54:10