Axios拦截器无法重发失败请求问题排查
问题分析与解决方案
核心问题
你当前的代码有两个关键问题导致重发请求不生效:
- 未等待刷新token的异步操作完成:
store.dispatch(refresh({}))是异步操作,但你直接在它后面调用重发请求,此时新的access token还没更新到Redux store里,refresh请求甚至可能还没完成,重发逻辑自然无法正常工作。 - 缺少防重复刷新机制:如果多个请求同时因token过期失败,会多次触发refresh请求,造成不必要的后端请求,也可能导致逻辑混乱。
另外注意变量名拼写错误:orginalRequest应该是originalRequest(语法上不报错,但属于不良编码习惯,建议修正)。
修正后的代码
创建实例与拦截器
import axios from 'axios'; import { store } from '../../../app/store'; import { refresh } from '../../auth/authSlice'; const axiosInstance = axios.create({ timeout: 5000 }) axiosInstance.defaults.baseURL = process.env.REACT_APP_BASE_SCRAPE_URL axiosInstance.defaults.withCredentials = true; // 防重复刷新标志 let isRefreshing = false; // 存储等待重发的请求队列 let failedRequestsQueue = []; axiosInstance.interceptors.request.use(function(config){ const state = store.getState(); const token = state.auth.accessToken; if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }) axiosInstance.interceptors.response.use(resp => resp, async error => { const originalRequest = error.config; // 修正拼写错误 // 仅处理token过期的情况,排除refresh请求本身避免死循环 if (error.response?.data === "Invalid Access Token" && !originalRequest._retry) { originalRequest._retry = true; // 标记已重试,防止死循环 if (!isRefreshing) { isRefreshing = true; try { // 等待refresh异步action完成,确保token已更新到store await store.dispatch(refresh({})).unwrap(); // 刷新完成后,批量重发队列中所有等待的请求 failedRequestsQueue.forEach(request => request.resolve(axiosInstance(request.config))); failedRequestsQueue = []; } catch (refreshError) { // 刷新失败,拒绝所有等待的请求 failedRequestsQueue.forEach(request => request.reject(refreshError)); failedRequestsQueue = []; // 这里可以添加登录页跳转等错误处理逻辑 window.location.href = '/login'; } finally { isRefreshing = false; } } // 将当前请求加入队列,等待token刷新后重发 return new Promise((resolve, reject) => { failedRequestsQueue.push({ resolve, reject, config: originalRequest }); }); } // 其他错误直接抛出 return Promise.reject(error); }) export default axiosInstance
关键修正点说明
- 等待refresh完成:用
await store.dispatch(refresh({})).unwrap()确保token完全更新到store后再处理重发,unwrap()用于捕获异步thunk的成功/失败状态。 - 请求队列与防重复:通过
isRefreshing避免重复触发refresh,用队列存储所有过期请求,刷新完成后批量重发,保证所有请求都能使用新token。 - 重试标记:给请求添加
_retry属性,防止重发后再次因token过期进入拦截器造成死循环。 - 拼写修正:统一变量名为
originalRequest,规范编码。
验证效果
修改后,当token过期时:
- 第一个失败请求触发refresh
- 后续失败请求进入队列等待
- 刷新成功后,队列中所有请求自动重发,且请求头会带上新token
- 刷新失败时,会执行登录跳转等错误逻辑
内容的提问来源于stack exchange,提问作者jamesc
相关产品推荐
相关产品推荐

