现在我正在处理网站身份验证,并且我已经添加了访问和刷新令牌。我想创建一个自动刷新操作来获取新的访问令牌。因此,如果我的服务器返回“访问被拒绝”错误,我想执行刷新并使用 RxJS 和 Redux Observable 重试之前的操作。
当我收到此错误时,我成功发出刷新请求(我正在遵循这些指南#1,#2)。 但是,我仍然不知道如何再次调用主操作。 我希望操作按照主操作、刷新、主操作(再次)的顺序执行,但目前只有两个正在执行三个动作。
这是我的代码,因此在catchError中调用handleError函数来请求新的访问令牌(如果需要)
const handleError = (action$: Observable<any>, err: any, caught: Observable<any>) => {
if (err.response?.errors?.[0]?.extensions?.code === "ACCESS_DENIED") {
return action$.pipe(
ofType(refreshSuccessActionCreator),
takeUntil(action$.pipe(ofType(LOGOUT_ACTION))),
take(1),
mergeMap(() => caught), //it is supposed to try main action again, but it don't
mergeWith(of(refreshActionCreator())), //calling refresh
);
}
else {
return of(workSessionErrorActionCreator(err));
}
};
//my epic
export const GetActiveWorkSessionEpic: Epic = (action$: Observable<PayloadAction<string>>) =>
action$.pipe(
ofType(GET_ACTIVE_WORK_SESSION_ACTION),
map(action => action.payload),
mergeMap((userId) => RequestGetActiveWorkSession(userId).pipe(
map(res => res.data?.workSession.getActiveWorkSessionByUserId),
map(workSession => SetActiveWorkSession(workSession)),
catchError((err, caught) => handleError(action$, err, caught)),
))
);
//action creators
export const refreshActionCreator = () => ({type: REFRESH_ACTION});
export const refreshSuccessActionCreator = () => ({type: REFRESH_SUCCESS_ACTION});
//refresh epic
export const RefreshEpic: Epic = (action$) =>
action$.pipe(
ofType(REFRESH_ACTION),
mergeMap(() => RequestRefresh().pipe(
map(res => {
if (res.data.auth.refresh) {
SetAccessToken(res.data.auth.refresh);
}
return refreshSuccessActionCreator();
}),
catchError(() => of(logoutActionCreator()))
))
);
另外,我不明白我的handleError史诗是如何工作的:
ofType()
中的动作类型?当我将操作类型放在这里时,它不起作用并无限地请求主要操作。mergeMap()
在这里没有效果?”我试图将
mergeMap
和mergeWith
更改为concatMap
和concatWith
。还在这里尝试了更多 rxjs 运算符,但它不起作用。尝试更改 pipe()
中的位置。我不能太多,因为我不明白这部史诗,但我已经花了很多时间在它上面。
- 为什么我必须在 ofType() 中传递 actionCreator 而不是动作类型?当我将操作类型放在这里时,它不起作用并无限地请求主要操作。
看起来主要问题隐藏在可观察的源中。
ofType
应该按您的预期工作。但可观察的源可能只会重复第一次失败,这将导致无限循环。要解决这个问题,请参阅第二个问题的答案。
- 为什么mergeMap()在这里没有效果?
mergeMap((userId) => RequestGetActiveWorkSession(userId).pipe(
行可能有问题。源可观察的RequestGetActiveWorkSession(userId)
显然不支持错误完成的重新订阅。
请将可观察源封装到
Observable.defer
,如参考指南中提到的那样。
引用指南 #1:
return Observable.defer(() => {
// we have to use defer to create a block that only gets executed when source get resubscribed to it.
return Observable.ajax(getData(data.id)) // api call to fetch data
})