React Native多API并行调用时Access Token刷新问题及崩溃修复
React Native Token 刷新问题解决方案
一、解决并行API重复刷新Token导致账号封禁问题
核心思路是用Promise缓存刷新请求,确保同一时间只有一个刷新Token的请求发送到后端,后续API请求等待该请求完成后复用结果。
实现步骤:
- 在全局 scope(比如API封装文件、状态管理模块)定义一个缓存刷新请求的Promise变量:
let refreshTokenPromise = null;
- 修改
getNewToken函数,利用该Promise控制请求唯一性:
const getNewToken = async (refToken: string) => { // 已有刷新请求在处理时,直接返回该Promise的结果 if (refreshTokenPromise) { return refreshTokenPromise; } let formattedEndpoint = ENDPOINT.LOGIN; let tokenVal = {}; const header = { refresh_token: refToken }; const requestQuery = { ...REFRESH_AUTH_HEADERS, ...header, }; const queryParams = new URLSearchParams({ ...requestQuery, }).toString(); formattedEndpoint = `${formattedEndpoint}?${queryParams}`; // 将刷新请求赋值给全局Promise,后续请求复用 refreshTokenPromise = api.post<LoginSuccess>( formattedEndpoint, {}, { headers: basicAuthHeaders, } ) .then(async refreshResponse => { if (refreshResponse.status === 200) { tokenVal = { access_token: refreshResponse.data?.access_token, refresh_token: refreshResponse.data?.refresh_token, expires_in: refreshResponse.data?.expires_in, type: 'private', }; } else { tokenVal = { access_token: null, token_type: null, refresh_token: null, expires_in: null, scope: null, id_token: null, type: 'public', }; tokenVal = await refreshPublicToken(); } return tokenVal; }) .catch(async error => { // 统一处理刷新失败的情况 tokenVal = await refreshPublicToken(); return Promise.reject(error); }) .finally(() => { // 请求完成后清空Promise,允许下次刷新 refreshTokenPromise = null; }); return refreshTokenPromise; };
二、解决多次调用logout()导致应用崩溃问题
通过状态标志位控制登出和页面跳转操作只执行一次,避免重复触发。
实现步骤:
- 在状态管理(比如Redux、Context)中添加
isLoggingOut状态,标记是否正在执行登出流程:
// 以Redux Slice为例 const authSlice = createSlice({ name: 'auth', initialState: { // ...其他状态 isLoggingOut: false, }, reducers: { setIsLoggingOut: (state, action) => { state.isLoggingOut = action.payload; }, // ...其他reducer }, }); export const { setIsLoggingOut } = authSlice.actions;
- 修改
logoutaction,添加状态判断避免重复执行:
export const logout = () => (dispatch, getState) => { const { isLoggingOut } = getState().auth; if (isLoggingOut) return; dispatch(setIsLoggingOut(true)); // 执行登出逻辑:清除Token、重置状态等 dispatch(setToken(null)); // ...其他登出操作 };
- 在
getNewToken和handleResponse的错误分支中,先判断状态再执行登出和跳转:
- 修改
getNewToken的错误分支:
else { const { isLoggingOut } = getState().auth; if (!isLoggingOut) { dispatch(logout()); navigation.dispatch(StackActions.replace(NAVIGATION_SCREENS.ROOT)); } tokenVal = { access_token: null, token_type: null, refresh_token: null, expires_in: null, scope: null, id_token: null, type: 'public', }; tokenVal = await refreshPublicToken(); }
- 修改
handleResponse的无效Token分支:
else { const { isLoggingOut } = getState().auth; if (!isLoggingOut) { setInvalidToken(true); navigation.dispatch(StackActions.replace(NAVIGATION_SCREENS.ROOT)); } return; }
内容的提问来源于stack exchange,提问作者Amal p
相关产品推荐
相关产品推荐

