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

如何用react-query/axios实现token过期自动刷新?

实现Token自动刷新的最佳方案(结合React Query + Axios)

要不要用状态管理?

不用额外引入Redux这类全局状态管理工具,React Query本身就能很好地管理token状态,配合Axios拦截器完全能搞定自动刷新逻辑。

核心实现思路

  • 用React Query统一处理token的获取与刷新,同时把token存在localStorage或sessionStorage里做持久化,避免页面刷新丢失。
  • 给Axios加请求拦截器,自动往请求头里塞Authorization;再加响应拦截器,捕获token过期的401错误,触发刷新逻辑后重试原请求。

具体代码实现

第一步:封装Axios实例

import axios from 'axios';

// 创建专属API实例
const api = axios.create({
  baseURL: '/your-api-base-url', // 替换成你的API基础地址
});

// 请求拦截器:自动添加Authorization头
api.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('accessToken');
    if (token) {
      config.headers.Authorization = token;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// 响应拦截器:处理token过期刷新
api.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    // 标记请求,避免重复触发刷新逻辑
    if (error.response.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      try {
        // 调用刷新token接口,传入旧token
        const oldToken = localStorage.getItem('accessToken');
        const refreshRes = await axios.post('/refresh-token', {}, {
          headers: { Authorization: oldToken }
        });
        const newToken = refreshRes.data.accessToken;
        localStorage.setItem('accessToken', newToken);
        // 更新原请求的token,重试请求
        originalRequest.headers.Authorization = newToken;
        return api(originalRequest);
      } catch (refreshError) {
        // 刷新失败,清除token并跳转登录页
        localStorage.removeItem('accessToken');
        window.location.href = '/login';
        return Promise.reject(refreshError);
      }
    }
    return Promise.reject(error);
  }
);

export default api;

第二步:用React Query处理登录获取初始Token

import { useMutation } from '@tanstack/react-query';
import api from './api';

export function useLogin() {
  return useMutation({
    mutationFn: (credentials) => api.post('/login', credentials),
    onSuccess: (res) => {
      const token = res.data.accessToken;
      localStorage.setItem('accessToken', token);
      
      // 可选:提前5分钟自动刷新token,避免用户操作时才触发
      const refreshTimer = 12 * 60 * 60 * 1000 - 5 * 60 * 1000;
      setTimeout(async () => {
        try {
          const refreshRes = await api.post('/refresh-token', {}, {
            headers: { Authorization: token }
          });
          localStorage.setItem('accessToken', refreshRes.data.accessToken);
        } catch (err) {
          localStorage.removeItem('accessToken');
          window.location.href = '/login';
        }
      }, refreshTimer);
    },
  });
}

第三步:用React Query调用业务接口

现在直接用封装好的api实例,不用手动加Authorization头:

import { useQuery } from '@tanstack/react-query';
import api from './api';

function useData() {
  return useQuery({
    queryKey: ['data'],
    queryFn: async () => {
      const res = await api.get('/endpoint');
      return res.data.data;
    },
  });
}

关键细节说明

  • 持久化选择:用localStorage存token,页面刷新后不会丢失;如果是敏感场景,换成sessionStorage更安全,关闭浏览器就自动清除。
  • 防重复刷新:给原请求加_retry标记,避免多个请求同时触发刷新逻辑,导致多次调用刷新接口。
  • 提前刷新优化:登录成功后设置定时器提前刷新token,能避免用户操作时突然出现401再刷新的卡顿感。
  • 异常兜底:如果刷新token接口也返回401,说明旧token彻底失效,直接清除token跳转登录页,避免死循环。

状态管理补充说明

如果你的应用只有简单的token管理需求,React Query + Axios拦截器完全够用,没必要额外加全局状态管理工具。但如果有复杂的用户信息、权限等全局状态需要共享,再考虑引入Redux或Zustand这类工具,但token刷新逻辑依然可以沿用上面的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 12:18:08