Angular 7 Error Interceptor - Проблема с исходным вызовом - PullRequest
0 голосов
/ 09 января 2019

Angular 7 Error Interceptor - Проблема с исходным вызовом Я написал перехватчик, чтобы перехватить все 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);
}

Intercepter

@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 Ответ

0 голосов
/ 11 января 2019

Я сталкиваюсь с довольно близкой проблемой, и я решаю ее с помощью 'switchmap' в 'pipe' с помощью 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 },
    ...
  ],
...
})
...