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

React+Node.js JWT认证:AccessToken过期自动刷新实现求助

Axios拦截器实现JWT自动刷新令牌方案

核心逻辑

通过Axios响应拦截器捕获accessToken过期导致的401请求,调用刷新接口获取新令牌,更新Cookie后重新发起原请求,同时通过锁机制避免重复刷新,用队列暂存等待请求保证操作连贯性。

具体代码实现

1. 创建Axios实例并初始化状态

import axios from 'axios';
import Cookies from 'js-cookie';

// 初始化Axios实例
const api = axios.create({
  baseURL: '/api', // 替换为你的后端接口前缀
});

// 刷新锁:防止同一时间多次调用刷新接口
let isRefreshing = false;
// 请求队列:暂存刷新期间需要重发的请求
let requestsQueue = [];

2. 请求拦截器:携带accessToken

api.interceptors.request.use(
  (config) => {
    const accessToken = Cookies.get('accessToken');
    if (accessToken) {
      config.headers.Authorization = `Bearer ${accessToken}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

3. 响应拦截器:处理令牌过期

api.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;

    // 仅处理未重试过的401请求,且排除刷新接口本身(避免死循环)
    if (error.response?.status === 401 && !originalRequest._retry) {
      if (isRefreshing) {
        // 若正在刷新,将当前请求加入队列等待重发
        return new Promise((resolve) => {
          requestsQueue.push(() => resolve(api(originalRequest)));
        });
      }

      originalRequest._retry = true;
      isRefreshing = true;

      try {
        // 调用刷新接口,后端自动从Cookie读取refreshToken
        const refreshRes = await axios.post('/api/refresh-token');
        const newAccessToken = refreshRes.data.accessToken;

        // 更新Cookie中的accessToken(有效期30秒)
        Cookies.set('accessToken', newAccessToken, { expires: 30 / 86400 });

        // 更新原请求的Authorization头
        originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;

        // 重发队列中所有等待的请求
        requestsQueue.forEach(callback => callback());
        requestsQueue = [];

        // 重发当前失败的请求
        return api(originalRequest);
      } catch (refreshErr) {
        // 刷新失败(如refreshToken过期),清除令牌并跳转登录页
        Cookies.remove('accessToken');
        Cookies.remove('refreshToken');
        window.location.href = '/login';
        return Promise.reject(refreshErr);
      } finally {
        isRefreshing = false;
      }
    }

    return Promise.reject(error);
  }
);

export default api;

关键注意事项

  • 防死循环:通过_retry标记确保同一请求只重试一次,同时排除刷新接口的请求拦截,避免递归调用。
  • 刷新锁:isRefreshing变量控制同一时间仅发起一次刷新请求,减少后端压力。
  • Cookie配置:确保后端设置refreshToken的Cookie时开启HttpOnly和SameSite,避免XSS风险;前端仅需操作accessToken的Cookie。
  • 失败处理:刷新失败必须清除现有令牌并跳转登录,避免陷入无限错误循环。
  • 请求队列:暂存刷新期间的请求,刷新完成后批量重发,保证用户操作流程不中断。

内容的提问来源于stack exchange,提问作者marco.bonaaa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 01:12:07