React Native中Axios刷新Token后无法重新发起请求问题求助
问题描述
- 在React Native中使用Axios发起携带accessToken的请求创建用户信息,已创建
axiosInstance并在请求头设置Authorization字段为accessToken - accessToken未过期时请求正常;返回401(token过期)后,能成功重新获取accessToken,但刷新后无法重新发起请求
- 已尝试方案:
- 更换Axios版本至v1.6.8
- 创建单例Promise确保仅发起一次刷新请求
用户提供的代码:
import axios from 'axios'; import EncryptedStorage from 'react-native-encrypted-storage'; const baseURL = '-'; const axiosInstance = axios.create({ baseURL }); let _refreshingPromise = null; const reissueToken = async () => { try { const refreshToken = await EncryptedStorage.getItem('refreshToken'); if (!refreshToken) { throw new Error("refreshToken doesnt exist"); } const response = await axios.post(`${baseURL}/auth/renew`, { refreshToken }); const newAccessToken = response.data.accessToken; await EncryptedStorage.setItem('accessToken', newAccessToken); return newAccessToken; } catch (error) { console.error("reissue failed ", error); throw error; } }; axiosInstance.interceptors.request.use( async (config) => { try { const accessToken = await EncryptedStorage.getItem('accessToken'); config.headers['Content-Type'] = 'application/json'; config.headers['Authorization'] = accessToken; console.log("original requests config:", config); return config; } catch (error) { console.error("request interceptor failed:", error); return Promise.reject(error); } }, (error) => { console.error("request interceptor error :", error); return Promise.reject(error); } ); axiosInstance.interceptors.response.use( (response) => { console.log("request succeed!"); return response; }, async (error) => { const { config,response } = error; const status = response? response.status : null; console.log("response status code : ", status); if(status === 502) { console.log("502 error"); } if (status === 401) { console.log("start!"); if (!_refreshingPromise) { console.log(_refreshingPromise); _refreshingPromise = new Promise((resolve, reject) => { reissueToken() .then((newAccessToken) => { console.log("newToken : ", newAccessToken); config.headers['Authorization'] = newAccessToken; console.log(config.headers.Authorization); axios(config) .then((response) => { console.log("response:", response.data); resolve(response); }) .catch((error) => { console.log("request failed!"); reject(error); }) .finally(() => { _refreshingPromise = null; }); }) .catch((reissueError) => { reject(new Error('error', reissueError)); }) .finally(() => { _refreshingPromise = null; }); }); } return _refreshingPromise; } return Promise.reject(error); } ); export default axiosInstance;
问题分析与修复方案
你的代码存在几个关键问题,导致刷新token后无法重新发起请求,以下是修复后的代码及说明:
修复后代码
import axios from 'axios'; import EncryptedStorage from 'react-native-encrypted-storage'; const baseURL = '-'; const axiosInstance = axios.create({ baseURL }); let _refreshingPromise = null; const reissueToken = async () => { try { const refreshToken = await EncryptedStorage.getItem('refreshToken'); if (!refreshToken) { throw new Error("refreshToken doesnt exist"); } const response = await axios.post(`${baseURL}/auth/renew`, { refreshToken }); const newAccessToken = response.data.accessToken; await EncryptedStorage.setItem('accessToken', newAccessToken); return newAccessToken; } catch (error) { console.error("reissue failed ", error); throw error; } }; axiosInstance.interceptors.request.use( async (config) => { try { // 跳过刷新token的请求,避免不必要的token获取逻辑 if (config.url.includes('/auth/renew')) { return config; } const accessToken = await EncryptedStorage.getItem('accessToken'); config.headers['Content-Type'] = 'application/json'; if (accessToken) { config.headers['Authorization'] = accessToken; } console.log("original requests config:", config); return config; } catch (error) { console.error("request interceptor failed:", error); return Promise.reject(error); } }, (error) => { console.error("request interceptor error :", error); return Promise.reject(error); } ); axiosInstance.interceptors.response.use( (response) => { console.log("request succeed!"); return response; }, async (error) => { const { config, response } = error; const status = response ? response.status : null; console.log("response status code : ", status); if (status === 502) { console.log("502 error"); } // 仅处理未标记为重试的401请求,避免循环触发刷新逻辑 if (status === 401 && !config._retry) { console.log("start!"); if (!_refreshingPromise) { _refreshingPromise = reissueToken() .then((newAccessToken) => { console.log("newToken : ", newAccessToken); // 标记请求为重试,防止再次进入401拦截逻辑 config._retry = true; config.headers['Authorization'] = newAccessToken; console.log(config.headers.Authorization); // 使用axiosInstance重发请求,复用已配置的拦截器和基础设置 return axiosInstance(config); }) .catch((reissueError) => { console.error("reissue and retry failed:", reissueError); throw reissueError; }) .finally(() => { // 统一清空刷新Promise,避免后续请求阻塞 _refreshingPromise = null; }); } return _refreshingPromise; } return Promise.reject(error); } ); export default axiosInstance;
关键修改点
- 改用
axiosInstance重发请求:原代码用全局axios(config)发起重发请求,没有复用你配置的axiosInstance的拦截器和基础设置,改为axiosInstance(config)后能正确走已有的请求逻辑。 - 添加重试标记避免循环:给config添加
_retry属性,确保401请求仅触发一次刷新逻辑,不会因为重发请求再次进入响应拦截器的401分支。 - 简化刷新Promise逻辑:去掉嵌套的Promise创建,直接返回
reissueToken的Promise链,避免异步逻辑混乱,同时统一在finally中清空_refreshingPromise,防止重复置空导致的问题。 - 跳过刷新请求的拦截器处理:在请求拦截器中判断如果是刷新token的请求,直接返回config,避免不必要的accessToken获取操作。
内容的提问来源于stack exchange,提问作者김민지
相关产品推荐
相关产品推荐

