在redux-saga中如何正确使用JWT refreshToken实现accesstoken过期刷新?
你的核心思路是合理的——access token过期后用refresh token换发新token再重试原请求,方向是对的,但现有实现存在几个明显缺陷,会导致逻辑不生效或者出现异常:
- 未过滤错误类型:当前所有请求错误都会触发token刷新逻辑,比如参数错误、无权限、网络断开等非token过期的错误也会走刷新逻辑,完全不符合预期。你需要先在catch块判断错误是否为token过期导致的403,最好是后端返回专门的错误码,确认是token过期才进入刷新流程。
- 未等待刷新流程完成就重试原请求:
put动作在saga中只是派发action,不会等待对应saga执行完成,你现在派发REFRESH_REQUEST之后立刻派发GETPOST_REQUEST,等于刷新token的请求还没返回,你就已经用旧的过期token重新发起了拉取帖子的请求,完全达不到刷新后重试的效果。 - 未处理刷新失败的场景:如果refresh请求也失败了,比如refresh token也过期了,当前逻辑没有任何兜底处理,用户侧会出现请求无响应的情况,这种场景下应该引导用户重新登录。
- 异步存储操作未等待完成:
AsyncStorage.setItem是异步操作,当前写法没有等待存储完成就认为刷新成功,可能出现新token还没写入存储,新请求就已经读取了旧token的问题。 - 重复刷新问题:如果同一时间有多个接口请求都返回token过期,会同时触发多次refresh请求,造成不必要的资源浪费,甚至部分后端实现中refresh token只能单次使用,多次请求会导致后续refresh直接失败。
优化后的参考实现
function* getPost(action) { try { const result = yield call(getPostAPI, action.data); yield put({ type: GETPOST_SUCCESS, data: result.data, }); } catch (err) { // 先判断是不是token过期的专属错误 if (err.response?.status === 403 && err.response.data?.code === 'ACCESS_TOKEN_EXPIRED') { try { // 直接调用refresh逻辑,等待刷新完成再往下走 const refreshResult = yield call(refreshAPI); // 等待token存储完成 yield call(AsyncStorage.setItem, 'accesstoken', `${refreshResult.data.accessToken}`); // 重试原请求 const retryResult = yield call(getPostAPI, action.data); yield put({ type: GETPOST_SUCCESS, data: retryResult.data, }); } catch (refreshErr) { // 刷新失败,抛出错误走兜底逻辑 yield put({ type: REFRESH_FAILURE, error: refreshErr.response.data }); // 此处补充跳转登录页的对应逻辑 } } else { // 其他错误正常处理 yield put({ type: GETPOST_FAILURE, error: err.response.data }) } } }
如果需要全局所有接口都需要做token过期刷新逻辑,更推荐封装axios拦截器统一处理,不用每个接口单独写重复逻辑。
内容的提问来源于stack exchange,提问作者user15322469
相关产品推荐
相关产品推荐

