Остановить трубу посередине

Dec 15 2020

В моем приложении angular у меня есть перехватчик обновления токена, который перехватывает 401-несанкционированные ошибки, пытается обновить токен доступа и снова выполняет исходный HTTP-запрос.

В некоторых случаях конечная точка обновления токена также может дать сбой и вернуть известную ошибку (в моем случае это ошибка 400 invalid_grant).

Часть перехватчика, обновляющая токен:

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

Когда это происходит, он переходит к оператору catchError, который выполняет 2 вещи: выходит из системы (с перенаправлением на страницу входа) и возвращает throwError (ошибка), эта ошибка, которую он выдает, является ошибкой 400-Invalid_grant.

Это приводит к тому, что новая ошибка поступает в некоторые операторы catchError в функциях, которые изначально запускали токен обновления.

Просто для контекста: я регистрирую ошибки в блоках catch и хочу избежать записи таких ошибок, потому что они обычно означают только то, что токен пользователя истек.

Я бы хотел как-то остановить эту цепочку операторов и просто перенаправить на страницу входа.

Возможно ли остановить канал посередине и избежать попадания как внешней catchError, так и следующего оператора в канале?

Ответы

1 GuerricP Dec 14 2020 at 23:25

Вы можете вернуть пустое значение, Observableчтобы предотвратить попадание событий или ошибок в компонент, который будет уничтожен:

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

Если я правильно понял вопрос, возможно, вам поможет оператор takeUntil . Пример будет выглядеть так:

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