Токен обновления JWT в Angular 7 — многократный вызов API в перехватчике HTTP

#javascript #angular #typescript #rxjs #jwt

#javascript #angular #typescript #rxjs #jwt

Вопрос:

Я реализую токен обновления JWT в своем проекте angular. Для этого я следую приведенному ниже руководству.

https://angular-academy.com/angular-jwt/

Вот мой код:

 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const user: any = this.storage.user;
    const addToken = !req.urlWithParams.includes('token');
    const token = user ? user.token : null;

    if (token amp;amp; !req.url.includes('token=') amp;amp; addToken) {
        req = this.addToken(req, user.token);
    }

    return next.handle(req).pipe(switchMap((event) => {
        if (event instanceof HttpResponse amp;amp; event.body.code === 401 amp;amp; token) {
            return this.handle401Error(req, next);
        }
        return next.handle(req);
    }));
}


private addToken(request: HttpRequest<any>, token: string) {
    return request.clone({
      setHeaders: {
        Authorization: `Bearer ${token}`,
      },
      setParams: {
        token
      }
    });
}


private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
  if (!this.isRefreshing) {
    this.isRefreshing = true;
    this.refreshTokenSubject.next(null);

    return this.getRefreshedJWT().pipe(
      switchMap((res: any) => {
        this.isRefreshing = false;
        this.refreshTokenSubject.next(res.token);
        return next.handle(this.addToken(request, res.token));
      }));

  } else {
    return this.refreshTokenSubject.pipe(
      filter(token => token != null),
      take(1),
      switchMap(jwt => {
        return next.handle(this.addToken(request, jwt));
      }));
  }
}


getRefreshedJWT() {
  const jwt_refresh_url = 'api/v3/token/refresh?token='   this.storage.user.token;
  
  return this.http.getFromAccountsApi(jwt_refresh_url)
      .pipe(tap((token) => {
      this.storeJwtToken(token);
  }));
}


private storeJwtToken(jwt: string) {
  const user = this.storage.user;
  user.token = jwt;
  this.storage.user = user;
}
  

Кстати. причина, по которой я не делаю этого внутри catchError , заключается в том, что наш серверный сервер структурирован так, как будто он всегда будет отправлять код состояния HTTP 200, а внутри этого ответа они будут отправлять пользовательский http-код на основе ошибок, таких как 401, 500 или успеха, такого как 200 и т. Д. Таким образом, он не войдет внутрь catchError , поскольку он ищет коды состояния HTTP, отличные от 200.

Теперь моя проблема заключается в том, что после реализации инициатора теперь мой API вызывается несколько раз. Смотрите Скриншот ниже:

введите описание изображения здесь

Застрял со вчерашнего дня и пока не нашел подходящего решения. Было бы здорово, если бы кто-нибудь мог указать, что я здесь делаю, и как мне это решить?

Если у вас есть какие-либо дополнительные запросы, дайте мне знать. Спасибо..

Комментарии:

1. «наш серверный сервер структурирован так, как будто он всегда будет отправлять код состояния HTTP 200, и внутри этого ответа они будут отправлять пользовательский код http на основе ошибок, таких как 401, 500 или успеха, такого как 200 и т. Д.» . Маскирование ответов о состоянии не является хорошей практикой..

2. @iLuvLogix я понимаю, но ничего не могу с этим поделать. Это корпоративное приложение, и они делают это уже 3-4 года. Вот как они построили свой сервер.

Ответ №1:

Совет для:

Кстати. причина, по которой я не делаю этого внутри catchError, заключается в том, что наш серверный сервер структурирован так, как будто он всегда будет отправлять код состояния HTTP 200, и внутри этого ответа они будут отправлять пользовательский http-код на основе ошибки, такой как 401, 500 или успеха, такого как 200 и т.д. Таким образом, он не попадет внутрь catchError, поскольку он ищет коды состояния HTTP, отличные от 200.

Вы можете выполнить сопоставление в ответе от сервера и проверить, есть ли ошибка, а затем выдать оттуда ошибку, тогда catchError должен работать на последовательных каналах.

Ошибка заключается в том, что вы возвращаете дескриптор в switchMap, вызывая повторный запрос.

 return next.handle(req);
  

Измените эту строку на:

 return of(event)
  

И это должно сработать