Angular 7エラーインターセプター–元の呼び出しの問題401エラーすべてをキャッチするインターセプターを作成しました。このようなエラーが発生した場合は、新しいJWTトークンの取得を試み、それが機能した場合は元のリクエストを繰り返します。これまでのところ、インターセプターは機能します。私の問題は、新しいトークンを与えた後の元のリクエストが、元のオブザーバブルに添付されたサブスクライブに再び到達しないことです。
元のリクエスト
成分:
this.serviceModel.getSearchItems(si).subscribe(res => {
this.resultData = res;
});
ServiceModel
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は元のサブスクライブの再実行に寄与するはずですが、機能しません。呼び出しは実行されますが、サブスクライブに到着しません。
私はかなり近い問題に直面しており、次のような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 },
...
],
...
})