Angular 7 错误拦截器 – 原始调用有问题
Posted
技术标签:
【中文标题】Angular 7 错误拦截器 – 原始调用有问题【英文标题】:Angular 7 Error Interceptor – Problem with original call 【发布时间】:2019-06-03 22:11:22 【问题描述】:Angular 7 错误拦截器 - 原始调用有问题 我编写了一个拦截器来捕获所有 401 错误。如果发生这样的错误,它应该尝试获取新的 JWT 令牌,如果成功,则重复原始请求。到目前为止,拦截器工作。我的问题是,在我给它新令牌之后的原始请求不会再次出现在订阅中,它附加到原始可观察对象。
原始请求
组件:
this.serviceModel.getSearchItems(si).subscribe(res =>
this.resultData = res;
);
服务模型
public getSearchItems(si: SearchInfo): Observable<VoList<SearchResultItemVO>>
return this.post<VoList<SearchResultItemVO>>(`/api/Search/GetSearchItems`, si, null, SearchResultItemVO);
拦截器
@Injectable()
export class ErrorInterceptor implements HttpInterceptor
constructor(private serviceModel: SharedAccountServiceModel)
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
return next.handle(request).catch(err =>
return this.handleError(err, request, next);
);
handleError(err, request: HttpRequest<any>, next: HttpHandler)
if (err.status === 401)
if (!!localStorage.getItem('auth_token') && !!localStorage.getItem('refresh_token'))
this.serviceModel.refreshlogin().switchMap(res =>
return next.handle(this.addAuthenticationToken(request));
)
.subscribe();
else
localStorage.removeItem('accessinfo');
localStorage.removeItem('auth_token');
localStorage.removeItem('userid');
location.reload(true);
const error = err.error.message || err.statusText;
return throwError(error);
addAuthenticationToken(request)
const accessToken = localStorage.getItem('auth_token');
if (!accessToken)
return request;
return request.clone(
setHeaders:
Authorization: `Bearer $localStorage.getItem('auth_token')`
);
据我了解,switchMap 应该有助于再次执行原始订阅,但它不起作用。调用已执行,但未到达订阅。
【问题讨论】:
【参考方案1】:我面临着非常接近的问题,我使用“管道”中的“switchmap”解决了这个问题,HttpInterceptor 像这样:
HttpErrorFilter :
import BehaviorSubject, Observable, of, throwError from 'rxjs';
import HttpEvent, HttpHandler, HttpInterceptor, HttpRequest from '@angular/common/http';
import catchError, filter, finalize, switchMap, take from 'rxjs/operators';
import AuthenticationService from './../services/authentication.service';
import Injectable from '@angular/core';
@Injectable()
export class HttpErrorFilter implements HttpInterceptor
isRefreshingToken = false;
tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);
constructor(private authenticationService: AuthenticationService)
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
return next.handle(request).pipe(
catchError((error: any) =>
if (error.status === 401 && !request.url.includes('auth/signin'))
return this.handle401Error(request, next);
return throwError(error);
)
);
private handle401Error(request: HttpRequest<any>, next: HttpHandler)
if (request.url.includes('auth/refreshtoken'))
this.isRefreshingToken = false;
return of(<any>this.authenticationService.logout());
if (!this.isRefreshingToken)
this.isRefreshingToken = true;
this.tokenSubject.next(null);
return this.authenticationService.refresh().pipe(switchMap(token =>
if (token)
this.tokenSubject.next(token.value);
return next.handle(request);
return of(<any>this.authenticationService.logout());
),
catchError(err =>
this.authenticationService.logout();
return throwError(err.error);
),
finalize(() =>
this.isRefreshingToken = false;
));
else
this.isRefreshingToken = false;
return this.tokenSubject
.pipe(filter(token => token != null),
take(1),
switchMap(token =>
return next.handle(request);
));
HttpFilter :
import HttpEvent, HttpHandler, HttpInterceptor, HttpRequest from '@angular/common/http';
import Injectable from '@angular/core';
import Observable from 'rxjs';
import environment from './../../../environments/environment';
@Injectable()
export class HttpFilter implements HttpInterceptor
private apiUrl = environment.apiUrl;
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
return next.handle(this.addAuthentication(request));
private addAuthentication(request: HttpRequest<any>): HttpRequest<any>
if (!request.url.includes('/auth/'))
const token = localStorage.getItem('access.token');
if (token)
request = request.clone(
setHeaders: Authorization: 'Bearer ' + token
);
return request.clone(url: `$this.apiUrl$request.url`);
NgModule 提供:
@NgModule(
...
providers: [
provide: HTTP_INTERCEPTORS, useClass: HttpErrorFilter, multi: true ,
provide: HTTP_INTERCEPTORS, useClass: HttpFilter, multi: true ,
...
],
...
)
【讨论】:
以上是关于Angular 7 错误拦截器 – 原始调用有问题的主要内容,如果未能解决你的问题,请参考以下文章
Angular 7 - 如何在某些响应状态代码上重试 http 请求?