Угловой 6: вызов службы Observer.next из Http Interceptor вызывает бесконечный цикл запроса - PullRequest
0 голосов
/ 23 ноября 2018

Я работаю на веб-сайте с аутентификацией с использованием JWT.Я создал класс перехватчика HTTP, который добавляет токен ко всем заголовкам запросов и используется для перехвата ошибок 401.

import {Injectable} from '@angular/core';
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable, of} from 'rxjs';
import {JwtService} from '../service/jwt.service';
import {catchError} from 'rxjs/operators';
import {AlertService} from '../../shared/service/alert.service';
import {Router} from '@angular/router';
import {AlertType} from '../../shared/model/alert.model';

@Injectable()
export class HttpTokenInterceptor implements HttpInterceptor {

  constructor(private jwtService: JwtService, private alertService: AlertService, private router: Router) {
  }

  /**
   * Intercept HTTP requests and return a cloned version with added headers
   *
   * @param req incoming request
   * @param next observable next request
   */
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    // Add headers to all requests
    const headersConfig = {
      'Accept': 'application/json'
    };

    // Add token bearer to header when it's available
    const token = this.jwtService.getToken();
    if (token) {
      headersConfig['Authorization'] = `Bearer ${token}`;
      headersConfig['Content-Type'] = 'application/json';
    }

    const request = req.clone({setHeaders: headersConfig});

    // Return adjusted http request with added headers
    return next.handle(request).pipe(
      catchError((error: any) => {

        // Unauthorized response
        if (error.status === 401) {

          this.handleError();
          return of(error);
        }
        throw error;
      })
    );
  }

  /**
   * Handle http errors
   */
  private handleError() {

    // Destroy the token
    this.jwtService.destroyToken();

    // Redirect to login page
    this.router.navigate(['/login']);

    // This is causing infinite loops in HTTP requests
    this.alertService.showAlert({
      message: 'Your token is invalid, please login again.',
      type: AlertType.Warning
    });

  }

}

Класс использует мой класс JwtToken для удаления токена из localstorage и перенаправления пользователяна страницу входа в систему с помощью углового маршрутизатора.Метод showAlert из alertService вызывает бесконечное повторение http-запроса.

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

import {Injectable} from '@angular/core';
import {Alert} from '../model/alert.model';
import {Subject} from 'rxjs';

/**
 * Alert Service: Used for showing alerts all over the website
 * Callable from all components
 */
@Injectable()
export class AlertService {

  public alertEvent: Subject<Alert>;

  /**
   * AlertService constructor
   */
  constructor() {
    this.alertEvent = new Subject<Alert>();
  }

  /**
   * Emit event containing an Alert object
   *
   * @param alert
   */
  public showAlert(alert: Alert) {
    this.alertEvent.next(alert);
  }
}

Класс alertService используется компонентом alert, который отображает все предупреждающие сообщения.Этот компонент используется в двух основных компонентах: Dashboard & login.

import {Component} from '@angular/core';
import {AlertService} from '../../shared/service/alert.service';
import {Alert} from '../../shared/model/alert.model';

@Component({
  selector: '*brand*-alerts',
  templateUrl: './alerts.component.html',
})
export class AlertsComponent {

  // Keep list in global component
  public alerts: Array<Alert> = [];

  constructor(private alertService: AlertService) {

    // Hook to alertEvents and add to class list
    alertService.alertEvent.asObservable().subscribe(alerts => {
      // console.log(alerts);
      this.alerts.push(alerts);
    });
  }

}

На следующем рисунке отчетливо видна проблема:

видео цикла

С уважением.

Редактировать: решено

На странице, которая выполнила запрос, на службу оповещений была инициирована подписка, что вызвало запрос http наогонь сноваУ меня просто есть компонент alert, который сейчас является единственным подписчиком на alertService, и я создал новый сервис для обновления.Ответ от @incNick действительно является правильной реализацией.Спасибо!

1 Ответ

0 голосов
/ 23 ноября 2018

Извините, что я занят своей работой, но, возможно, мой источник может помочь.

import { Observable, throwError } from 'rxjs';
import { tap, catchError } from 'rxjs/operators';
...
return httpHandler.handle(request).pipe(
          tap((event: HttpEvent<any>) => {
              if (event instanceof HttpResponse) { 
                  //this.loadingService.endLoading();
              }
          },
          (err: any) => {
              //this.loadingService.endLoading();
          }),
          catchError((err: any) => {
              if (err.status === 401) {
                  /*
                  this.modalController.create({
                      component: LoginComponent,
                      componentProps: {returnUrl: this.router.url},
                      showBackdrop: true
                  }).then(modal => modal.present());
                  */
              } else {
                  //this.messageService.showToast(`Some error happen, please try again. (Error-${err.status})`, 'error');
              }
              return throwError(err);
          })
      );

Я возвращаю throwError (err) в конце.

...