React 18中Axios响应拦截器失效,重新请求未带token求助
问题描述
React 18项目中使用Axios响应拦截器实现token刷新逻辑时出现异常:
- 刷新token接口能正常返回新的
idToken,且已更新存储,但重新发起请求时,请求头未携带Authorization字段 - 打印
error.response.config显示Authorization已正确设置,但实际请求仍缺失该字段,导致请求陷入无限循环 - 相同代码在React 16项目中可正常运行
相关代码如下:
响应拦截器代码
axios.interceptors.response.use( (response) => { return response; }, (error) => { if (error.response.status === 401) { let usersData = JSON.parse(localStorage.getItem("userData")); const refreshToken = usersData.refreshToken; return axios .post( `${api_base_url}/auth/authentication/refresh_token`, JSON.stringify({ refresh_token: refreshToken, }) ) .then((response) => { usersData["accessToken"] = response.data.data.accessToken; usersData["idToken"] = response.data.data.idToken; setSessionStorage("userData", usersData); error.response.config.headers[ "Authorization" ] = `Bearer ${response.data.data.idToken}`; return axios(error.response.config); }) .catch((error) => { if (error.response.data.code !== "TOKEN_EXPIRED") { return; } localStorage.clear(); window.location = "/login"; }); } return Promise.reject(error); } );
请求封装代码
function getIRequestProp(severType, isMultipart, isSocial) { const serverUrl = severType ? social_api_base_url : api_base_url; let userData = JSON.parse(localStorage.getItem('userData')); let idToken; idToken = userData !== null ? userData['idToken'] : ''; let content_type; if (isSocial) { content_type = 'application/x-www-form-urlencoded' } else { content_type = isMultipart ? 'multipart/form-data' : 'application/json' } return { serverUrl: serverUrl, requestHeader: { 'Content-Type': content_type, 'Accept-Language': DEFAULT_LANGUAGE, Authorization: `Bearer ${idToken}` } }; } async function post(url, body, isSocialServer, isMultipart) { const {serverUrl, requestHeader} = getIRequestProp(isSocialServer, isMultipart); return axios.post(serverUrl + url, body, { headers: requestHeader }); }
API调用示例
AxiosServices.post(ApiUrlServices.SOCIALS_UPDATE_LINKS(UserInfo.userId), payload, false) .then(response => {})
问题排查与解决方案
1. 存储介质不一致(核心问题)
拦截器中更新token后使用setSessionStorage("userData", usersData)存储,但请求封装方法getIRequestProp是从localStorage读取token,这会导致:
- 若存在未贴出的请求拦截器,它可能会重新从
localStorage读取旧token,覆盖手动设置的新值 - 后续通过封装方法发起的请求也会拿到旧token
修复方式:统一存储介质,将拦截器中的存储代码改为:
localStorage.setItem("userData", JSON.stringify(usersData));
2. Axios Config对象不可变性问题
部分Axios版本中,error.response.config可能是冻结对象,直接修改headers属性可能不生效。需创建新的headers对象覆盖原配置:
// 替换原直接赋值的代码 error.response.config.headers = { ...error.response.config.headers, Authorization: `Bearer ${response.data.data.idToken}` };
3. 添加防重复刷新标识,避免无限循环
在拦截器中添加自定义标识,防止同一请求多次进入401刷新逻辑:
axios.interceptors.response.use( (response) => { return response; }, (error) => { if (error.response.status === 401) { // 避免重复触发刷新逻辑 if (error.response.config._isRefreshing) { return Promise.reject(error); } error.response.config._isRefreshing = true; let usersData = JSON.parse(localStorage.getItem("userData")); const refreshToken = usersData.refreshToken; return axios .post( `${api_base_url}/auth/authentication/refresh_token`, JSON.stringify({ refresh_token: refreshToken, }) ) .then((response) => { usersData["accessToken"] = response.data.data.accessToken; usersData["idToken"] = response.data.data.idToken; localStorage.setItem("userData", JSON.stringify(usersData)); error.response.config.headers = { ...error.response.config.headers, Authorization: `Bearer ${response.data.data.idToken}` }; // 清除标识,允许后续请求正常触发刷新 delete error.response.config._isRefreshing; return axios(error.response.config); }) .catch((error) => { delete error.response.config._isRefreshing; if (error.response.data.code !== "TOKEN_EXPIRED") { return Promise.reject(error); } localStorage.clear(); window.location = "/login"; }); } return Promise.reject(error); } );
4. 检查Axios版本兼容性
React 18项目可能使用了更高版本的Axios(如v1.x),与React 16项目中的旧版本(如v0.x)存在config处理差异:
- 确认
config.headers的结构,确保Authorization字段大小写正确(首字母大写) - 检查是否存在全局请求拦截器,若有需确认其逻辑是否会覆盖手动设置的
Authorization头
内容的提问来源于stack exchange,提问作者kazinayem2011
相关产品推荐
相关产品推荐

