【问题标题】:Global ErrorHandler is not working after implementing catchError in ngrx effect在ngrx效果中实现catchError后全局ErrorHandler不起作用
【发布时间】:2019-07-12 21:27:31
【问题描述】:

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

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

//错误处理程序

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 运算符,以便在发生错误时不会中断效果,并使用全局错误处理程序来显示不同的错误消息。

【问题讨论】:

  • 由于您在 ngrx 效果中捕获错误,因此它不会传播到全局错误处理程序。你想实现什么,为什么你期望在全局处理程序中出现错误?
  • 我想使用全局处理程序显示错误。有什么方法可以在不破坏ngrx/effect的情况下使用错误处理程序来处理错误。
  • 如果你只是从ngrx效果中删除catchError,你的意思是它会破坏效果吗?
  • 如果我删除了 catchError,那么 ngrx/effect 将在第一个错误发生后停止工作。检查这个问题:stackoverflow.com/a/41685689/5404825
  • 哦,是的,你是对的。但我认为由于错误已被捕获,因此无法将其传播到全局错误处理程序。相反,我可以建议您根据您的状态在 UI 上显示错误。这意味着当您调度 EffectError 时,这可以在 reducer -> 中设置“失败”状态,并基于此在 UI 中显示错误消息。

标签: angular typescript error-handling rxjs ngrx


【解决方案1】:

问题在于@Effect 中的catchError 会吞下错误,并且不会传播回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://medium.com/angular-in-depth/expecting-the-unexpected-best-practices-for-error-handling-in-angular-21c3662ef9e4

【讨论】:

    【解决方案2】:

    假设您的全局错误处理程序如下:

    @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;
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多