如何在redux-saga中使用yield解决token存储时序异常问题
问题根因
你遇到的问题由两个错误用法导致:
- redux-saga 中
put方法是非阻塞的,你在捕获到jwt过期后连续触发REFRESH_REQUEST和GETPOST_REQUEST两个action,refresh逻辑还没执行完,新的getPost请求已经发起,自然拿不到更新后的token - 你直接
yield AsyncStorage.setItem没有用call包装,saga不会等待这个异步存储操作执行完成,就会提前触发REFRESH_SUCCESS动作
解决步骤
1. 改造refresh saga,确保token存储完成后再结束流程
将异步存储操作用saga的call方法包装,阻塞saga执行直到token写入AsyncStorage完成:
function* refresh() { try { const result = yield call(refreshAPI); // 用call包装异步方法,saga会等待存储完成再往下执行 yield call(AsyncStorage.setItem, 'accesstoken', `${result.data.accessToken}`); // 可选:如果你的refreshToken也会更新,这里同步存储refreshToken yield put({ type: REFRESH_SUCCESS, data: result.data, }); } catch (err) { yield put({ type: REFRESH_FAILURE, error: err.response.data, }); } }
2. 改造getPost的异常处理逻辑,等待refresh流程完全结束后再重发请求
用saga的take方法监听refresh的结束动作,确保refresh跑完再发起新的业务请求:
function* getPost(action) { try { const result = yield call(getPostAPI, action.data); yield put({ type: GETPOST_SUCCESS, data: result.data, }); } catch (err) { if (err.response.data === 'jwtEx') { yield put({ type: REFRESH_REQUEST, }); // 阻塞等待refresh流程结束(成功/失败都要等) const refreshAction = yield take([REFRESH_SUCCESS, REFRESH_FAILURE]); // 只有refresh成功才重发请求,失败的话可以按业务逻辑处理登出/提示 if (refreshAction.type === REFRESH_SUCCESS) { yield put({ type: GETPOST_REQUEST, data: action.data, }); } else { // 这里可以加refresh失败的处理,比如清空存储跳转到登录页 yield put({ type: GETPOST_FAILURE, error: '登录状态已过期,请重新登录', }); } } else { yield put({ type: GETPOST_FAILURE, error: err.response.data, }); } } }
补充说明
你现有axios.js的拦截器逻辑不需要修改,只要保证请求发起时token已经写入AsyncStorage,拦截器就能读到最新的token值附加到请求头。
内容的提问来源于stack exchange,提问作者jack volten
相关产品推荐
相关产品推荐

