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

React中如何检测access token过期并使用refresh token处理401错误?

Access Token过期自动刷新实现方案

实现思路

通过axios的拦截器统一处理所有请求的token携带和异常响应:

  • 请求拦截器:每次发起请求前读取最新的access token添加到请求头,避免使用固定配置导致token更新后不生效
  • 响应拦截器:捕获401过期错误,使用refresh token换取新的access token后自动重试失败的请求,同时加锁避免多个请求同时触发token刷新逻辑

完整代码实现

1. 封装axios公共实例与拦截器

创建单独的api配置文件,比如src/utils/request.js:

import axios from 'axios';

// 替换为你的接口基础域名
const BASE_URL = '你的后端接口基础地址';

// 创建自定义axios实例,统一配置通用参数
const api = axios.create({
  baseURL: BASE_URL,
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  }
});

// 请求拦截器:自动携带最新的access token
api.interceptors.request.use(
  (config) => {
    const accessToken = localStorage.getItem('accessToken');
    if (accessToken) {
      config.headers.Authorization = `Bearer ${accessToken}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// 刷新token锁,避免重复调用刷新接口
let isRefreshing = false;
// 存储刷新token期间的待重试请求队列
let retryRequestQueue = [];

// 响应拦截器:处理token过期逻辑
api.interceptors.response.use(
  // 请求成功直接返回响应
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    // 判断是否为access token过期的401错误,且未重试过
    if (
      error.response?.status === 401 &&
      error.response.data?.message === 'jwt expired' &&
      !originalRequest._retry
    ) {
      // 已经在刷新token,将当前请求加入队列等待刷新完成后重试
      if (isRefreshing) {
        return new Promise((resolve) => {
          retryRequestQueue.push((newAccessToken) => {
            originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
            resolve(api(originalRequest));
          });
        });
      }

      // 标记请求已重试,开启刷新锁
      originalRequest._retry = true;
      isRefreshing = true;

      try {
        const refreshToken = localStorage.getItem('refreshToken');
        // 调用后端刷新token接口,替换为你的实际接口地址和参数格式
        const refreshRes = await axios.post(`${BASE_URL}/refresh-token`, { refreshToken });
        const { accessToken: newAccessToken, refreshToken: newRefreshToken } = refreshRes.data;

        // 更新本地存储的token
        localStorage.setItem('accessToken', newAccessToken);
        localStorage.setItem('refreshToken', newRefreshToken);

        // 执行队列中所有待重试的请求
        retryRequestQueue.forEach((cb) => cb(newAccessToken));
        retryRequestQueue = [];

        // 重试当前失败的请求
        originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
        return api(originalRequest);
      } catch (refreshErr) {
        // refresh token也过期,清空本地存储跳转登录页
        localStorage.removeItem('accessToken');
        localStorage.removeItem('refreshToken');
        window.location.href = '/login';
        return Promise.reject(refreshErr);
      } finally {
        // 重置刷新锁
        isRefreshing = false;
      }
    }
    // 非token过期的错误直接抛出
    return Promise.reject(error);
  }
);

export default api;

2. 业务请求改写

原有业务代码直接引入封装好的api实例调用即可,不需要单独配置请求头:

import api from 'src/utils/request';

const getAllProducts = async () => {
  const response = await api.get('/getProducts');
  // 处理返回数据
  return response.data;
};

注意事项

  • 请根据后端实际规则调整刷新token的接口地址、请求参数、返回字段,以及401错误的判断逻辑
  • 原有代码中${url}/ getProducts的路径多了多余空格,需修正为正确的接口路径
  • 若项目使用React Router路由,可以替换window.location.href的跳转逻辑为路由跳转方法,体验更友好

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 14:54:02