angular - 在拦截器中刷新令牌时管道 catchError 不起作用
问题描述
问这可能是一个愚蠢的问题,但我创建了一个拦截器,如果响应失败并显示代码 401 并使用 api 刷新令牌,我会在其中捕获。它工作正常,但如果由于某种原因刷新令牌 api 也失败,我也想捕获错误,这里是代码
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) { }
isRefreshingToken: boolean = false;
tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any> | any> {
return next.handle(this.addTokenToRequest(request, this.authService.getJWT()))
.pipe(
catchError(err => {
if (err instanceof HttpErrorResponse) {
switch ((<HttpErrorResponse>err).status) {
case 401:
return this.handle401Error(request, next);
case 400:
return <any>this.authService.logout();
}
} else {
return throwError(err);
}
}));
}
private addTokenToRequest(request: HttpRequest<any>, token: string): HttpRequest<any> {
return request.clone({ setHeaders: { Authorization: `Bearer ${token}` } });
}
private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
if (!this.isRefreshingToken) {
this.isRefreshingToken = true;
// Reset here so that the following requests wait until the token
// comes back from the refreshToken call.
this.tokenSubject.next(null);
return this.authService.refreshToken()
.pipe(
switchMap((refreshToken: any) => {
console.log('here');
if (refreshToken) {
this.tokenSubject.next(refreshToken.token);
this.authService.setJWT(refreshToken.token);
this.authService.setRefreshToken(refreshToken.refreshToken);
// localStorage.setItem('currentUser', JSON.stringify(user));
return next.handle(this.addTokenToRequest(request, refreshToken.token));
}else{
}
return <any>this.authService.logout();
}),
catchError(err => {
console.log('here', err);
return <any>this.authService.logout();
}),
finalize(() => {
console.log('here');
this.isRefreshingToken = false;
})
);
} else {
this.isRefreshingToken = false;
return this.tokenSubject
.pipe(filter(token => token != null),
take(1),
switchMap(token => {
return next.handle(this.addTokenToRequest(request, token));
}));
}
}
}
注意在调用它的行上,如果失败return this.authService.refreshToken()
,它不会到达 catchErrorrefreshToken()
我知道它可能只会在原始请求失败时到达 catchError 。所以在服务中我试图从刷新令牌api中捕获错误,代码如下:
refreshToken(): Observable<any> {
let jwt = this.getJWT();
let refreshToken = this.getRefreshToken();
debugger;
return this.http.post<any>(this.api.REFRESH_TOKEN, { refreshToken: refreshToken, expiredToken: jwt })
.pipe(
map(result => {
console.log('here');
debugger;
return result;
}),
catchError(e => {
debugger;
console.log(e, 'here');
return null;
})
);
}
如果刷新令牌 api 失败,它甚至没有达到这一点,我的问题是如何从刷新令牌 api 捕获错误并将用户重定向到登录。谢谢。
解决方案
你必须在你的switchMap中移动你的catchError块,把catchError放在Observable管道的第一级不是一个好的错误处理方法,如果catchError在Observable管道方法的第一级,将调用finalize操作符
.pipe(switchMap((refreshToken: any) => {
console.log('here');
if (refreshToken) {
this.tokenSubject.next(refreshToken.token);
this.authService.setJWT(refreshToken.token);
this.authService.setRefreshToken(refreshToken.refreshToken);
// localStorage.setItem('currentUser', JSON.stringify(user));
return next.handle(this.addTokenToRequest(request, refreshToken.token)).pipe(
catchError(err => {
console.log('here', err);
return <any>this.authService.logout();
})
);
}
else{}
return <any>this.authService.logout();
}),
finalize(() => {
console.log('here');
this.isRefreshingToken = false;
})
推荐阅读
- typo3 - 遮罩流体 ViewHelper 不渲染它
- r - 正则表达式替换 R 中字符串的部分/组
- cmd - 运行“net user”user“/domain”命令并以经典 asp 读取结果
- ruby-on-rails-3.2 - 将 rails 3.1.10 升级到 3.2.0 时堆栈级别太深
- php - AJAX 上传文件与进度 + FFMPEG 进度
- asp.net - ASP.NET Identity,授权成功后如何更改视图
- python - 从python中的文本文件中获取搜索行后2行的行
- python - 重新采样/时间分组到特定的时间跨度/周期
- javascript - 动态生成的 sql 查询的安全性
- javascript - Axios Promise 究竟何时解决