пропустить обработчики перехватчика, если в ответе произошла ошибка - PullRequest
0 голосов
/ 31 марта 2020

проблема. Когда я делаю недействительным токен refre sh на сервере и приходит запрос токена refre sh, я получаю следующее предупреждение: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

Это действительно происходит, когда запрос не выполняется с 401 Unauthorized. Сложная часть, которая, вероятно, неправильна, здесь:

                catchError((error: any) => {
                  this.convertErrorToAppError(error);
                  return of(null);
                })

На самом деле, мне здесь не нужно catchError, я хочу, чтобы произошла ошибка 401 - она ​​должна быть перехвачена на верхнем уровне перехватчика используя метод convertErrorToAppError. И это работает, но выдает предупреждение (You provided 'undefined'...) как ошибку вместо Unauthorized.

import {
  HttpRequest,
  HttpHandler,
  HttpInterceptor,
  HttpErrorResponse
} from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, throwError, of } from 'rxjs';
import { catchError, mergeMap } from 'rxjs/operators';

// import { ToastsService } from '../services/toasts';
import { AuthService } from '../services/auth.service';

// Errors
import { BadRequest } from '../errors/response-errors/bad-request';
import { NotAcceptable } from '../errors/response-errors/not-acceptable';
import { NotFound } from '../errors/response-errors/not-found';
import { Unauthorized } from '../errors/response-errors/unauthorized';
import { AppError } from '../errors/app-error';
import { NoConnection } from '../errors/no-connection';
import { Store } from '@ngxs/store';
import { SaveAccessAndRefreshTokens } from '../store/auth/actions';
import { AuthModel } from '../store/auth/model';
import { NewAccessTokenResponse } from '../store/auth/interfaces/new-access-token-response';
import { JwtHelperService } from '@auth0/angular-jwt';
import { UiService } from '../services/ui.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(
    private authService: AuthService,
    private store: Store,
    private uiService: UiService
  ) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
    return this.handle(req, next).pipe(
      catchError((error: any) => {
        this.convertErrorToAppError(error);
        return of(null);
      })
    );
  }

  private handle(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
    // If request does not have authorization header then pass it
    if (
      !req.headers.get('authorization') ||
      req.url.endsWith('/renew-access-token') ||
      req.url.endsWith('/login')
    ) {
      return next.handle(req);
    }

    return this.store
      .selectOnce((state: any) => {
        return state.auth;
      })
      .pipe(
        mergeMap((state: AuthModel) => {
          if (state.token) {
            const jwtHelper = new JwtHelperService();
            if (!jwtHelper.isTokenExpired(state.token)) {
              return next.handle(req);
            } else {
              console.log('renewAccessToken 1');
              return this.authService.renewAccessToken(state.refreshToken).pipe(
                mergeMap((response: NewAccessTokenResponse) => {
                  this.store.dispatch(new SaveAccessAndRefreshTokens(response));
                  const newReq = req.clone({
                    setHeaders: {
                      authorization: 'Bearer ' + response.token
                    }
                  });
                  return next.handle(newReq);
                }),
                catchError((error: any) => {
                  this.convertErrorToAppError(error);
                  return of(null);
                })
              );
            }
          }
        }),
        catchError((error: any) => {
          if (error instanceof HttpErrorResponse) {
            if (error.status === 401) {
              // JWT expired, go to login
              if (error.error.message === 'Expired JWT Token') {
                return this.store
                  .selectOnce((state: any) => {
                    return state.auth;
                  })
                  .pipe(
                    mergeMap((state: AuthModel) => {
                      console.log('renewAccessToken 2');
                      return this.authService
                        .renewAccessToken(state.refreshToken)
                        .pipe(
                          mergeMap((response: NewAccessTokenResponse) => {
                            this.store.dispatch(
                              new SaveAccessAndRefreshTokens(response)
                            );
                            const newReq = req.clone({
                              setHeaders: {
                                authorization: 'Bearer ' + response.token
                              }
                            });
                            return next.handle(newReq);
                          })
                        );
                    })
                  );
              }
            }
          }
        })
      );
  }

  private convertErrorToAppError(error: any) {
    if (error instanceof HttpErrorResponse) {
      this.uiService.dismissLoading();
      if (error.status === 401) {
        // return throwError(new Unauthorized());
        throw new Unauthorized();
      }

      if (error.status === 400) {
        throw new BadRequest(error);
        // return throwError(new BadRequest(error));
      }

      if (error.status === 404) {
        throw new NotFound();
        // return throwError(new NotFound());
      }

      if (error.status === 406) {
        throw new NotAcceptable();
        // return throwError(new NotAcceptable());
      }

      if (error.status === 0) {
        console.error('Connection error...');
        throw new NoConnection();
        // return throwError(new NoConnection());
      }
      // return throwError(new AppError(error));
    }

    throw new AppError(error);
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...