在ngrx效果中实现catchError后,全局ErrorHandler无法工作

时间:2019-02-19 11:24:21

标签: angular typescript error-handling rxjs ngrx

我正在尝试处理我的angular应用程序中的错误,但是全局错误处理程序不起作用。

我正在使用ngrx进行状态管理,并且在我的angular应用程序中有一个全局错误处理程序。我正在使用catchError运算符按照建议的here处理ngrx / effects中的错误。但是现在我无法使用全局错误处理程序,并且必须在每个效果中都使用catchError。

// ErrorHandler

handleError(error: Error | HttpErrorResponse) {
  const router = this.injector.get(Router);
  console.error("Error intercepted.", error);
  this.spinner.hide();
  if (error instanceof HttpErrorResponse) {
     if (!navigator.onLine) {
        this.showError('No internet connection');
     } else {
        if (error.error.message) {
            this.showError(`${error.error.message}`);
        } else {
            this.showError(`${error.status} - ${error.message}`);
        }
     }
  } else {
     this.showError("Unknow error.");
     router.navigate(['/dashboard']);
    }
}

// ngrx效果

export class EffectError implements Action {
    readonly type = '[Error] Effect Error';
}

@Effect()
UserAuth: Observable < Action > = this.actions.pipe(
  ofType(SigninActions.AUTHENTICATE_USER),
  switchMap((action: SigninActions.AuthenticateUser) =>
    this.signinService.signin(action.payload.emailAddress, action.payload.password).pipe(
        map((loginContext: LoginContext) => {
            console.log("LOGIN_CONTEXT", loginContext);
            return new SigninActions.AuthenticateUserSuccess(loginContext)
        }),
        //CatchError
        catchError(() => of(new EffectError()))
    )
   )
);

我正在使用catchError运算符,以便每当发生错误并且全局错误处理程序显示不同的错误消息时,效果都不会中断。

2 个答案:

答案 0 :(得分:1)

问题是catchError中的@Effect吞噬错误,并且不会传播回ErrorHandler

您可以找到很多有关如何执行此操作的文章,但总而言之,您应该执行HttpInterceptor并使用catchError处理HttpHandler发回的错误:

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

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
      catchError(error => {
        if (error instanceof HttpErrorResponse) {
          // check for internet connection
          if (!navigator.onLine) {
            this.showError('No internet connection');
          }
          // handle HTTP errors
          switch (error.status) {
            case 401:
              // do something
              break;
            case 403:
              // do something else
              break;
            default:
              // default behavior
          }
        }
        // need to rethrow so angular can catch the error
        return throwError(error);
      }));
  }
}

然后,当然,不要忘记在AppModule中使用HTTP_INTERCEPTORS注入令牌来提供错误拦截器的实现:

import { HTTP_INTERCEPTORS } from '@angular/common/http';

...

providers: [
  { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
],

通过这种方式,您可以同时处理两个错误...

  • ErrorHandler用于客户端错误(javascript,角度等等)
  • HttpInterceptor用于HTTP请求

关于如何处理角度错误的好方法,这是一篇不错的文章:
https://blog.angularindepth.com/expecting-the-unexpected-best-practices-for-error-handling-in-angular-21c3662ef9e4

答案 1 :(得分:0)

假设您的globalerrorhandler如下:

@Injectable()
export class GlobalErrorHandler extends ErrorHandler {
  public handleError(error: Error | HttpErrorResponse) { }
}

您可以从catcherror中抛出错误(在您的效果中),并且现在将调用handleError方法。

example.effect.ts

catchError((err) => {
  const error: string = err.message;
  this.store.dispatch(exampleActions.ResultFailure({ error }));
  throw err;
})