如何用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
相关产品推荐
相关产品推荐

