高级描述
我有一个使用Google Oauth的React / redux /电子应用程序.我希望能够在到期时自动刷新访问令牌.我已经研究过这个并使用中间件半成功地解决了它,但我的解决方案在某些情况下是错误的.
我已经实现了一个在每个API动作上运行的刷新中间件.它会检查访问令牌是否已过期或即将过期.如果是,则不是分派它收到的动作,而是调度令牌刷新动作并将任何其他动作排队,直到收到新的访问令牌.之后,它将调度其队列中的所有操作.
但是,我的一个动作创建者看起来像这样:
function queryThreads(params) {
return async (dispatch) => {
const threads = await dispatch(fetchThreads(params))
const newPageToken = threads.payload.nextPageToken
}
}
当刷新中间件因为令牌未到期而未运行时,将在此处定义threads.payload,并且一切都将按预期工作.
但是,当刷新中间件运行时,threads.payload将是未定义的,因为调度似乎使用令牌刷新操作的值而不是fetchThreads操作来解析.
如何确保令牌被刷新(并在状态/ localStorage中更新),fetchThreads被更新的令牌调度,并且线程变量被分配给正确的Promise的已解析值?
项目代码的链接
0700年,它受到了this article的启发.
This is the token refresh action creator.
This is the line in my queryThreads action creator在令牌必须刷新时抛出(threads.payload未定义).
This is the reducer where I update state响应令牌刷新.
This is the middleware where I update localStorage响应令牌刷新.
最佳答案 看起来我已经通过重写刷新中间件解决了这个问题,如下所示:
function createRefreshMiddleware() {
const postponedRSAAs = [];
return ({ dispatch, getState }) => {
const rsaaMiddleware = apiMiddleware({ dispatch, getState });
return next => action => {
if (isRSAA(action)) {
try {
const auth = JSON.parse(localStorage.getItem('auth'));
const { refresh_token: refreshToken } = auth;
const expirationTime = jwtDecode(auth.id_token).exp * 1000;
const isAccessTokenExpiring =
moment(expirationTime) - moment() < 300000;
if (refreshToken && isAccessTokenExpiring) {
postponedRSAAs.push(action);
if (postponedRSAAs.length === 1) {
return rsaaMiddleware(next)(
dispatch(() => attemptTokenRefresh(refreshToken))
).then(() => {
const postponedRSAA = postponedRSAAs.pop();
return dispatch(postponedRSAA);
});
}
return rsaaMiddleware(next)(action);
}
return rsaaMiddleware(next)(action);
} catch (e) {
console.log(e);
return next(action);
}
}
return next(action);
};
};
}
export default createRefreshMiddleware();
现在,推迟的操作将始终与令牌刷新操作相关联,因此我们没有原始承诺解决错误值的问题;加上它更简洁.