Angular HTTP拦截器-无法从内部订阅返回 [英] Angular HTTP interceptor - Cannot return from inner subscription
问题描述
我正在尝试实现HTTP拦截器,因此当令牌过期时,我会得到refresh_token,然后调用 return next.handle(request);
,但看来我无法返回从主管.如果我尝试以/API_URL/page1的身份访问我的页面,并且返回401状态,那么我将获得刷新令牌,但应该再次调用/API_URL/page1,而不会.我使用"rxjs":"6.5.5"
.这是我的代码:
I am trying to implement an HTTP interceptor so when the token is expired, I get the refresh_token, and then I call return next.handle(request);
, but it seems like I cannot return from the main pipe.
If I try to access my page as /API_URL/page1 and this returns a 401 status, I then get the refresh token, but /API_URL/page1 should be called again and it is not. I use "rxjs": "6.5.5"
. This is my code:
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const currentUser = this.lsService.getItem('currentUser') as any;
if(currentUser && currentUser.accessToken && this.checkIfUrlNeedsToken(request)) {
request = request.clone({ headers: request.headers.set('Authorization', currentUser.accessToken) });
}
return next.handle(request)
.pipe(tap(
(event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
// do stuff with response if you want
}
}, (err: any) => {
if(this.isRefreshTokenExpiredError(err)) {
this.redirectToLogin();
} else if(this.isAuthError(err) && this.checkIfUrlNeedsToken(request)) {
return this.authService.getNewToken().subscribe((response: User): Observable<HttpEvent<any>> => {
this.lsService.setItem('currentUser', response); // Rewrite the current user
request = request.clone({ headers: request.headers.set('Authorization', response.accessToken) });
return next.handle(request);
});
} else {
this.redirectToLogin();
}
}
));
}
请告知.谢谢!
推荐答案
您不能从订阅中返回值-您必须使用 switchMap
或 concatMap
.
You can't return a value from a subscribe - you have to return the observable from within the pipe using either a switchMap
or a concatMap
.
此外, tap
正在产生副作用.您不能从 tap
返回.在您的情况下,您需要从 catchError
返回.
Also, tap
is performing side-effects. You cannot return from a tap
. In your case you will need to return from a catchError
.
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const currentUser = this.lsService.getItem('currentUser') as any;
if(currentUser && currentUser.accessToken && this.checkIfUrlNeedsToken(request)) {
request = request.clone({ headers: request.headers.set('Authorization', currentUser.accessToken) });
}
return next.handle(request)
.pipe(
tap((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
// do stuff with response if you want
}
}, (err: any) => {
if (this.isRefreshTokenExpiredError(err)) {
this.redirectToLogin();
} else if(this.isAuthError(err) && this.checkIfUrlNeedsToken(request)) {
// handle in catchError
} else {
this.redirectToLogin();
}
}),
catchError((err: any) => {
if(!this.isAuthError(err) || !this.checkIfUrlNeedsToken(request)) {
return throwError(err);
}
return this.authService.getNewToken().pipe(
switchMap((response: User): Observable<HttpEvent<any>> => {
// Rewrite the current user
this.lsService.setItem('currentUser', response);
request = request.clone({ headers: request.headers.set('Authorization', response.accessToken) });
return next.handle(request);
});
})
);
}
通过管道的错误操作流程现在类似于:
The flow of error actions through the pipe is now something like:
- 点击:如有必要,重定向
- catchError:如有必要,获取新令牌
- switchMap:重新运行http请求
我已将可观察对象移动到
catchError
内的switchMap
中.我没有在tap
中更改您的任何逻辑-现在可以简化了.I have moved the observable into a
switchMap
inside acatchError
. I haven't changed any of your logic inside thetap
- that can probably be simplified now.这篇关于Angular HTTP拦截器-无法从内部订阅返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!