HttpInterceptor в Angular 4.3: перехват 400 ошибок

Я хотел бы перехватить 401 и другие ошибки, чтобы соответственно реагировать. Это мой перехватчик:

import { LoggingService } from './../logging/logging.service';
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpResponse, HttpErrorResponse } from '@angular/common/http';

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';

@Injectable()
export class TwsHttpInterceptor implements HttpInterceptor {

    constructor(private logger: LoggingService) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        this.logger.logDebug(request);    
        return next.handle(request)
            .do(event => {
                if (event instanceof HttpResponse) {
                    this.logger.logDebug(event);
                }
            });
    }
}

Хотя это хорошо работает для 200 запросов, оно не перехватывает ошибки respsonses

Все, что я вижу в консоли chrome dev, это:

zone.js: 2616 GET http://localhost: 8080/backend/rest/misurl 404 (не найдено)

Или это

zone.js: 2616 GET http://localhost: 8080/backend/rest/url 401 (неавторизованный)

Я хотел бы, чтобы мой перехватчик справился с этим. Что мне не хватает?

Ответ 1

Http посылает ошибки вниз поток ошибок наблюдаемой так что вам нужно будет поймать их с .catch (вы можете прочитать об этом здесь).

return next.handle(request)
  .do(event => {
    if (event instanceof HttpResponse) {
      this.logger.logDebug(event);
    }
  })
  .catch(err => { 
    console.log('Caught error', err);
    return Observable.throw(err);
  });

Ответ 2

Это, вероятно, слишком поздно для вас использовать, но, надеюсь, кто-то еще найдет это полезным... Вот как переписать вышеприведенный оператор возврата для ответов об ошибках журнала:

return next.handle(request).do((event: HttpEvent<any>) => {
  if (event instanceof HttpResponse) {
    this.logger.logDebug(event);
  }
}, (error: any) => {
  if (error instanceof HttpErrorResponse) {
    this.logger.logDebug(error);
  }
});

Я использую эту же методологию, чтобы автоматически отправлять все 401 несанкционированные ответы непосредственно на наш метод выхода из системы (вместо проверки на 401 при каждом индивидуальном вызове на http):

return next.handle(request).do((event: HttpEvent<any>) => {
  if (event instanceof HttpResponse) {
    // process successful responses here
  }
}, (error: any) => {
  if (error instanceof HttpErrorResponse) {
    if (error.status === 401) {
      authService.logout();
    }
  }
});

Он работает как абсолютный шарм. :)

Ответ 3

В то время я пробовал Angular 7+.

К сожалению, вышеприведенные решения не .do так как .do напрямую не доступен в HttpHandler с точки зрения RxJs 6 pipe; и преобразование Observable to Promise не прилипает.

Здесь чистый и современный подход; Я pipe catchError оператора и анализировать ошибки и, наконец, снова бросить его с помощью throwError. Вот окончательная форма перехватчика;

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).pipe(
      catchError((error: HttpErrorResponse) => {
        if (error.error instanceof ErrorEvent) {
          // client-side error or network error

        } else {
          // TODO: Clean up following by introducing method
          if (error.status === 498) { 
            // TODO: Destroy local session; redirect to /login
          }
          if (error.status === 401) { 
            // TODO: Permission denied; show toast
          }
        }
        return throwError(error);
      })
    );
  }

Надеемся, что это решение поможет кому-то в будущем.

Ответ 4

Чтобы перехватить ошибку ответа Http в угловом 6, я делаю небольшой трюк, переводящий Observable to Promise:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
   const obs = next.handle(req);

   if (!window.navigator.onLine) {
     // Handle offline error
     this.messageService.showError('No Internet Connection');
     return;
   }

   obs.toPromise().catch((error) => {
     this.messageService.progress(false);
     this.messageService.showError(error.message);
   });
   return obs;
}