Angular HTTP перехватчик - не удается вернуться из внутренней подписки - PullRequest
0 голосов
/ 03 апреля 2020

Я пытаюсь реализовать перехватчик HTTP, поэтому, когда срок действия токена истек, я получаю refresh_token, а затем я вызываю return next.handle(request);, но кажется, что я не могу вернуться из основного канала. Если я пытаюсь получить доступ к своей странице как / API_URL / page1, и это возвращает статус 401, я получаю токен refre sh, но / API_URL / page1 должен вызываться снова, и это не так. Я использую "rxjs": "6.5.5". Это мой код:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const currentUser = this.lsService.getItem('currentUser') as any;

    if(currentUser && currentUser.accessToken && this.checkIfUrlNeedsToken(request)) {
      request = request.clone({ headers: request.headers.set('Authorization', currentUser.accessToken) });
    }

    return next.handle(request)
      .pipe(tap(
        (event: HttpEvent<any>) => {
          if (event instanceof HttpResponse) {
            // do stuff with response if you want
          }
        }, (err: any) => {
          if(this.isRefreshTokenExpiredError(err)) {
            this.redirectToLogin();
          } else if(this.isAuthError(err) && this.checkIfUrlNeedsToken(request)) {
            return this.authService.getNewToken().subscribe((response: User): Observable<HttpEvent<any>> => {
              this.lsService.setItem('currentUser', response);  //  Rewrite the current user
              request = request.clone({ headers: request.headers.set('Authorization', response.accessToken) });
              return next.handle(request);
            }); 
          } else {
            this.redirectToLogin();
          }
        }
      ));
  }

Пожалуйста, сообщите. Спасибо!

1 Ответ

2 голосов
/ 03 апреля 2020

Вы не можете вернуть значение из подписки - вы должны вернуть наблюдаемое изнутри канала, используя switchMap или concatMap.

Кроме того, tap выполняет сторону -последствия. Вы не можете вернуться с tap. В вашем случае вам нужно будет вернуться с catchError.

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  const currentUser = this.lsService.getItem('currentUser') as any;

  if(currentUser && currentUser.accessToken && this.checkIfUrlNeedsToken(request)) {
    request = request.clone({ headers: request.headers.set('Authorization', currentUser.accessToken) });
  }

  return next.handle(request)
    .pipe(
      tap((event: HttpEvent<any>) => {
        if (event instanceof HttpResponse) {
          // do stuff with response if you want
        }
      }, (err: any) => {
        if (this.isRefreshTokenExpiredError(err)) {
          this.redirectToLogin();
        } else if(this.isAuthError(err) && this.checkIfUrlNeedsToken(request)) {
          // handle in catchError
        } else {
          this.redirectToLogin();
        }
      }),
      catchError((err: any) => {
        if(!this.isAuthError(err) || !this.checkIfUrlNeedsToken(request)) {
          return throwError(err);
        }

        return this.authService.getNewToken().pipe(
          switchMap((response: User): Observable<HttpEvent<any>> => {
            //  Rewrite the current user
            this.lsService.setItem('currentUser', response); 
            request = request.clone({ headers: request.headers.set('Authorization', response.accessToken) });
            return next.handle(request);
          }); 
      })
    );
  }

Поток действий с ошибками через канал теперь выглядит примерно так:

  • tap: перенаправить при необходимости
  • catchError: при необходимости получить новый токен
    • switchMap: перезапустить http-запрос

Я переместил наблюдаемое в switchMap внутри catchError. Я не изменил ни одной вашей логики c внутри tap - это, вероятно, теперь можно упростить.

...