Возврат переделанного звонка после обновления токена JWT - PullRequest
0 голосов
/ 24 мая 2019

Я использую JWT и у меня есть эта логика:

  1. Сделайте http-звонок
  2. Возвращает 401, если токен был уничтожен или результат
  3. При возвращении 401 мне нужно сделать http-вызов, чтобы потребовать новый токен
  4. Повторите начальный вызов с новым токеном
  5. Вернуть результат

Вся эта процедура должна быть скрыта для пользователя. Я уже перехватил код состояния 401 и повторил исходный вызов после получения нового токена, проблема в том, чтобы вернуть результат исходному вызову. Это сервис с запросом http:

    getListCategories(){
        return this.http.get<Category[]>("/api/configuration/category").pipe(
          catchError(err =>  this.handleError.handleError(err, { severity: 'error', summary: 'Error retrieving the list of categories', life: 5000 }))
        );
    }

это перехватчик ошибок, который выполняет вызов обновления и повторяет исходный вызов:

    export class ErrorInterceptorService implements HttpInterceptor {

      constructor(private auth: AuthService, public router: Router) { }

      intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const { shouldRetry } = this;
        return next.handle(request).pipe(
          retryWhen(genericRetryStrategy({
            shouldRetry
          })),

          catchError(err => {
            //401 the token is invalid so I have to refresh it
            if (err.status === 401 && request.url !== "/api/login") {
              this.auth.refreshToken().subscribe(
                (apiResult: SessionTokenResponse) => {
                  this.auth.saveToken(apiResult.token);
                  request = request.clone({ headers: request.headers.set('Authorization', 'Bearer ' + apiResult.token) });
                  next.handle(request).subscribe();
                },
              );
            } else if (err.status === 401 && request.url === "/api/login") {
              this.auth.logout()
            }else{
              const error = err.error.message || err.statusText;
              return throwError(error);
            }
          }),
        )
      }
      private shouldRetry = (error) => (error.error instanceof ErrorEvent);
    }

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

1 Ответ

1 голос
/ 24 мая 2019

Вы хотите вернуть Observable с цепочечными операциями, которые включали дополнительный запрос между исходным и повторным запросом. Я бы попытался сделать это, используя switchMap.

Было бы что-то вроде этого:

catchError(err => {
            if (err.status === 401 && request.url !== "/api/login") {
              //by returning observable here, you are "chaining" the calls so original caller will get this observable's result. `catchError` can be threated like `catch` block in `try-catch` where you can still do operations and return results - ergo continue operations.
              return this.auth.refreshToken()
                .switchMap( // this just switches from one observable to another
                (apiResult: SessionTokenResponse) => {
                  this.auth.saveToken(apiResult.token);
                  request = request.clone({ headers: request.headers.set('Authorization', 'Bearer ' + apiResult.token) });
                  return next.handle(request); // return original request handler with updated headers
                },
              );

Очевидно, что не проверено и может иметь неверный синтаксис, как написано здесь.

...