刷新令牌后,我尝试重播失败的请求。 以下this 作为指导。
我的http拦截器:
isRefreshingToken: boolean = false
tokenSubject: Subject<void> = new Subject<void>()
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(this.tokenRequest(req)).pipe(
catchError((error) => {
if (error instanceof HttpErrorResponse) {
if (error.status === HttpStatusCode.Unauthorized) {
if (!this.isRefreshingToken) {
this.isRefreshingToken = true
this.dialog.open(LoginDialog).afterClosed().subscribe(() => {
// at this point there is a new token in my token service
this.isRefreshingToken = false
this.tokenSubject.next()
})
}
return this.tokenSubject.pipe(
switchMap(() => {
return next.handle(this.tokenRequest(req))
})
)
}
}
return throwError(() => error)
})
)
}
tokenRequest(req: HttpRequest<any>): HttpRequest<any> {
const token = // get token from service
return req.clone({ headers: req.headers.set('Authorization', `Bearer ${token}`) });
}
这是有效的,通过对话框登录后,失败的请求将被重播。 然而,订阅永远不会从发出原始请求的客户端触发。
httpService.getStuff().subscribe(() => {
// I am never called if the error request that was caught in the interceptor was retried
})
因此,在出现错误和令牌刷新的情况下,我从 http 拦截器返回的可观察值似乎不正确。 有什么想法吗?
拦截器不会等待所有异步操作完成,它可能只需要第一次发射。您需要在组件级别编写此代码才能使其工作。建议减少过于复杂的代码并给出
retry(1)
这可以简化您的要求。
api$.pipe(
retry(1)
).subscribe({
next: (val: any) => console.log(val),
error: (error: any) => console.log(error),
complete: () => console.log('complete'),
});