Ferma una pipa nel mezzo

Dec 15 2020

Nella mia app angolare, ho un intercettatore di aggiornamento del token che intercetta gli errori 401-Unauthorized, tenta di aggiornare un token di accesso ed esegue nuovamente la richiesta http originale.

Anche l'endpoint di aggiornamento del token potrebbe non riuscire in alcuni casi e restituire un errore noto (nel mio caso è un errore 400 invalid_grant).

La parte dell'interceptor che aggiorna il 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
    })
  );

Quando ciò accade, arriva a un operatore catchError, che fa 2 cose: logout (con reindirizzamento alla pagina di accesso) e restituisce throwError (errore), questo errore che genera è l'errore 400-Invalid_grant.

Ciò fa sì che il nuovo errore arrivi ad alcuni operatori catchError nelle funzioni che originariamente hanno attivato il token di aggiornamento.

Solo per contesto: registro gli errori nei blocchi catch e voglio evitare di registrare questo tipo di errori, perché di solito significano solo che il token dell'utente è scaduto.

Quello che vorrei fare è fermare in qualche modo questa catena di operatori e reindirizzare semplicemente alla pagina di accesso.

È possibile fermare un pipe nel mezzo ed evitare sia di arrivare a un catchError esterno che al prossimo operatore nel pipe?

Risposte

1 GuerricP Dec 14 2020 at 23:25

È possibile restituire un vuoto Observableper evitare che eventi o errori raggiungano un componente che sta per essere distrutto:

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

Se ho capito bene la domanda, forse un operatore takeUntil può aiutarti. L'esempio sarà simile a questo:

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();
             ...
         }
      )
  }
}