angular - Angular HTTP 拦截器 - 无法从内部订阅返回
问题描述
我正在尝试实现一个 HTTP 拦截器,所以当令牌过期时,我得到了 refresh_token,然后我调用return next.handle(request);
了,但似乎我无法从主管道返回。如果我尝试以 /API_URL/page1 的身份访问我的页面并且返回 401 状态,那么我将获得刷新令牌,但 /API_URL/page1 应该再次被调用,但事实并非如此。我用"rxjs": "6.5.5"
. 这是我的代码:
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();
}
}
));
}
请指教。谢谢!
解决方案
您不能从订阅返回值 - 您必须使用 aswitchMap
或 a从管道内返回可观察对象concatMap
。
此外,tap
正在执行副作用。您不能从tap
. 在您的情况下,您将需要从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);
});
})
);
}
通过管道的错误操作流程现在类似于:
- 点击:必要时重定向
- catchError:必要时获取新令牌
- switchMap:重新运行http请求
我已将 observable 移动到 a switchMap
inside acatchError
中。我没有改变你在里面的任何逻辑tap
- 现在可能可以简化了。
推荐阅读
- javascript - Web Worker 部署后不工作,但在本地工作
- mysql - ERD:如何存储三种不同支付类型的数据
- c++ - 通过指针问题
- ios - 无法从不需要的通信扩展 iOS 访问钥匙串
- python - 尽管提升为以管理员身份运行,PyCharm 仍引发权限错误
- asp.net - ASP.NET Core 2.1 Jwt 设置自定义声明
- javascript - 如何让 Google Tag Manager 事件跟踪发送到 Google Analytics?
- c++ - 未找到 extern 声明的模板专用函数
- haskell - 如果列表包含一些可被 42 整除的值,使用 'any' 来告诉你真/假
- javascript - 无法删除事件侦听器 Javascript