React Native中Axios刷新Access Token后仍报401错误求助
问题:Access Token过期后刷新Token仍无法获取分类数据
当前代码在Access Token未过期时能正常获取分类数据,但当Access Token过期触发401错误后,调用刷新Token函数更新Access和Refresh Token后,仍然返回[AxiosError: Request failed with status code 401]错误,以下是相关代码及问题分析:
相关代码
1. 刷新Token函数
export async function refreshTokenGenerator() { const url = RefreshCurrentTokenURL; const refreshTokenGeneratedFirst = newUser.getRefreshToken(); const response = await axios .post(url, { refreshToken: refreshTokenGeneratedFirst, }) .catch((error) => { console.log( "🚀 ~ file: auth.js:118 ~ refreshTokenGenerator ~ error cant refresh token", error ); }); const newRefreshTokenGenerated = response.data.refreshToken; // 将新生成的Refresh Token赋值给用户模型 // Refresh Token循环正常,覆盖RT无错误 const assignNewRefreshTokenToUserModel = newUser.setRefreshToken( newRefreshTokenGenerated ); // Access Token循环正常 // 当收到401错误时调用,因为这代表AT已过期 const newAccessTokenGenerated = response.data.token; return newAccessTokenGenerated; }
2. 更新AccessToken函数
export async function updateAccessToken() { console.log("updateAccessToken called"); const newGeneratedTokenAfterExpiration = await refreshTokenGenerator(); newUser.setToken(newGeneratedTokenAfterExpiration); const userToken = newGeneratedTokenAfterExpiration; return userToken; }
3. 菜单认证与获取分类函数
async function authenticateMenu() { const url = CategoriesAuthUrl; let userToken = newUser.getToken(); const authStr = "Bearer ".concat(userToken); const options = { method: "GET", headers: { Authorization: authStr, }, url: url, }; const response = await axios(options).catch(async (error) => { if (error.response.status === 401) { // 应调用刷新Token的函数来更新Access和Refresh Token console.log("Error 401 unauthorized"); const newUserToken = await updateAccessToken(); userToken = newUserToken; } console.log( "😡 ~ file: menu.js:28 ~ authenticateMenu ~ Error getting categories from API call", error ); }); const fetchedCategories = response.data; console.log( "🚀 ~ file: menu.js:40 ~ authenticateMenu ~ fetchedCategories", fetchedCategories ); return fetchedCategories; } // 获取分类 export async function getCategories() { return authenticateMenu(); }
4. HomeScreen调用代码
useEffect(() => { async function fetchCatHandler() { const categoriesFetched = await getCategories().catch((error) => { console.log( "🟥 ~ file: HomeScreen.js:63 ~ fetchCatHandler ~ error from fetching categories from Home screen", error ); }); setParsedCategories(categoriesFetched); } fetchCatHandler(); async function getUserName() { setUserName(await newUser.getUserName()); } getUserName(); }, []);
问题分析与解决方案
核心问题
- 未重新发起请求:在
authenticateMenu的catch块中,仅更新了userToken但未用新Token重新发送请求,原请求已失败,response仍处于错误状态或为undefined,后续读取response.data会直接报错。 - 刷新Token函数未处理请求失败场景:
refreshTokenGenerator中若axios请求失败,catch仅打印日志无返回值,导致response为undefined,后续读取response.data会抛出错误。
修复方案
方案1:修复authenticateMenu函数,刷新Token后重新请求
修改函数逻辑,在刷新Token后用新Token重新发起请求:
async function authenticateMenu() { const url = CategoriesAuthUrl; let userToken = newUser.getToken(); try { const authStr = "Bearer ".concat(userToken); const response = await axios({ method: "GET", headers: { Authorization: authStr }, url: url, }); return response.data; } catch (error) { if (error.response?.status === 401) { console.log("Error 401 unauthorized, refreshing token..."); // 刷新Token const newUserToken = await updateAccessToken(); // 用新Token重新发起请求 const newAuthStr = "Bearer ".concat(newUserToken); const response = await axios({ method: "GET", headers: { Authorization: newAuthStr }, url: url, }); return response.data; } console.log("😡 ~ file: menu.js:28 ~ authenticateMenu ~ Error getting categories from API call", error); throw error; // 抛出错误让上层处理 } }
方案2:完善refreshTokenGenerator的错误处理
避免请求失败时response为undefined导致后续报错:
export async function refreshTokenGenerator() { const url = RefreshCurrentTokenURL; const refreshTokenGeneratedFirst = newUser.getRefreshToken(); try { const response = await axios.post(url, { refreshToken: refreshTokenGeneratedFirst, }); const newRefreshTokenGenerated = response.data.refreshToken; newUser.setRefreshToken(newRefreshTokenGenerated); const newAccessTokenGenerated = response.data.token; return newAccessTokenGenerated; } catch (error) { console.log("🚀 ~ file: auth.js:118 ~ refreshTokenGenerator ~ error cant refresh token", error); throw error; // 抛出错误让上层处理,比如跳转登录页 } }
方案3:推荐使用Axios拦截器统一处理Token刷新(更优雅)
设置全局响应拦截器,统一处理401错误,无需在每个请求中重复写逻辑:
// 创建Axios实例 const api = axios.create({ baseURL: '你的API基础地址' }); // 请求拦截器:自动添加Token api.interceptors.request.use( (config) => { const token = newUser.getToken(); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => Promise.reject(error) ); // 响应拦截器:处理401刷新Token api.interceptors.response.use( (response) => response, async (error) => { const originalRequest = error.config; // 避免重复刷新Token if (error.response?.status === 401 && !originalRequest._retry) { originalRequest._retry = true; try { const newToken = await refreshTokenGenerator(); newUser.setToken(newToken); originalRequest.headers.Authorization = `Bearer ${newToken}`; // 重新发起原请求 return api(originalRequest); } catch (refreshError) { // 刷新Token失败,跳转到登录页 console.log("Refresh token failed, redirect to login"); // 这里添加跳转登录的逻辑,比如navigation.navigate('Login') return Promise.reject(refreshError); } } return Promise.reject(error); } ); // 之后使用api实例发起请求 async function authenticateMenu() { const response = await api.get(CategoriesAuthUrl); return response.data; }
内容的提问来源于stack exchange,提问作者Zakaria
相关产品推荐
相关产品推荐

