Zatrzymaj rurę na środku

Dec 15 2020

W mojej aplikacji kątowej mam przechwytywacz odświeżania tokenu, który przechwytuje błędy 401-nieautoryzowane, próbuje odświeżyć token dostępu i ponownie wykonuje pierwotne żądanie http.

Punkt końcowy odświeżania tokenu może również w niektórych przypadkach zakończyć się niepowodzeniem i zwrócić znany błąd (w moim przypadku jest to błąd 400 invalid_grant).

Część przechwytywacza, która odświeża token:

 return this.httpClient
  .request('POST', "token", { observe: 'response' })
  .pipe(
    map(response => {
      // some logic when the token was refreshed successfully
    }),
    catchError(err => {
      this.routingService.navigateToLoginNoQuery();
      return throwError(err); // a 400 - invalid_grant error
    })
  );

Kiedy tak się dzieje, trafia do operatora catchError, który wykonuje 2 rzeczy: wylogowanie (z przekierowaniem do strony logowania) i zwraca throwError (błąd), ten zgłoszony błąd to błąd 400-Invalid_grant.

Powoduje to, że nowy błąd pojawia się w niektórych operatorach catchError w funkcjach, które pierwotnie wyzwoliły token odświeżania.

Tylko dla kontekstu: rejestruję błędy w blokach catch i chcę uniknąć rejestrowania tego rodzaju błędów, ponieważ zwykle oznaczają one tylko utratę ważności tokenu użytkownika.

Chciałbym w jakiś sposób zatrzymać ten łańcuch operatorów i po prostu przekierować na stronę logowania.

Czy jest możliwe zatrzymanie rury w środku i uniknięcie zarówno dostania się do zewnętrznego catchError, jak i do następnego operatora w rurze?

Odpowiedzi

1 GuerricP Dec 14 2020 at 23:25

Możesz zwrócić puste, Observableaby zapobiec przedostawaniu się zdarzeń lub błędów do komponentu, który ma zostać zniszczony:

return this.httpClient
  .request('POST', "token", { observe: 'response' })
  .pipe(
    map(response => {
      // some logic when the token was refreshed successfully
    }),
    catchError(err => {
      this.routingService.navigateToLoginNoQuery();
      return EMPTY;
    })
  );
MishaBorisov Dec 14 2020 at 23:30

Jeśli dobrze zrozumiałem pytanie, być może operator takeUntil może ci pomóc. Przykład będzie wyglądał tak:

export class MyHttpInterceptor implements HttpInterceptor {
  anyError = new Subject();

  intercept(req: HttpRequest, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req)
      .pipe(
         takeUntil(this.anyError),
         catchError(err => {
             this.anyError.next();
             ...
         }
      )
  }
}