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

