如何在Angular中实现全局ErrorHandler和HttpInterceptor ?



我在网上发现ErrorHandler可以捕获所有错误作为客户端错误和httpErrorResponse错误。

但是在我的情况下,我只能在GlobalErrorHandlerService中捕获客户端错误,另一个httpErrorResponse不能被捕获。我做错了什么?

我app-module:

providers: [
{ provide: HTTP_INTERCEPTORS, useClass: MainInterceptorService, multi: true },
{ provide: ErrorHandler, useClass: GlobalErrorHandlerService  },
],
bootstrap: [AppComponent]
})
export class AppModule { }

我GlobalErrorHandler:

import {ErrorHandler, Injectable} from '@angular/core';
import {HttpErrorResponse} from "@angular/common/http";
@Injectable({
providedIn: 'root'
})
export class GlobalErrorHandlerService implements ErrorHandler{
constructor() { }
handleError(error: any): void {
console.log("Handler work")
if (error instanceof HttpErrorResponse){
console.log("HttpErrorResponse")
} else {
console.log("Not httpErrorResponse")
}
}
}

我的拦截器:

import { Injectable } from '@angular/core';
import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from "@angular/common/http";
import {catchError, Observable, throwError} from "rxjs";
import {error} from "@angular/compiler-cli/src/transformers/util";
@Injectable({
providedIn: 'root'
})
export class MainInterceptorService implements HttpInterceptor{
private httpError = {
status: 0,
message: ''
};
constructor() { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// req=req.clone({headers:req.headers.set("Auth","Bearer"+token)})
return next.handle(req).pipe(
catchError(
(error:HttpErrorResponse|Error)=>{
// server-side error
if (error instanceof HttpErrorResponse){
console.log("intercepter work")
return throwError(()=>new Error("Server side error"+error));
} else {
return throwError(()=>new Error("Client side error"+error))
}
}
)
)
}
}

我UserService

import { Injectable } from '@angular/core';
import {HttpClient, HttpErrorResponse} from "@angular/common/http";
import {User} from "../entity/user";
@Injectable({
providedIn: 'root'
})
export class UserService {
errors:any[]|undefined
private response:Response|undefined
constructor(private http:HttpClient) { }
readonly URL_BASE="http://****"
readonly URL_REGISTRATE="http://****"
registrUser(user:User):any {
return this.http.post<any>(this.URL_BASE+"/account/register", user)
}
loginUser(userName:string,password:string):any{
return this.http.post<any>(this.URL_BASE+"/account/signin",{userName,password})
}
}

如果你能解释一下ErrorHandler的逻辑,那就太好了。

我想我现在明白你的代码是怎么回事了:

首先
  • 你的MainInterceptorService被调用。如果您得到一个服务器错误,您可以将HttpErrorResponse转换为Error-对象。
  • 第二>,您的GlobalErrorHandlerService被击中,但由于您已经将错误转换为类型为Error的对象,它将不再被识别为HttpErrorResponse,因此它被视为客户端错误。我还注意到:当我在registrUser()loginUser()中添加catchError()时,GlobalErrorHandlerService而不是因为本地catchError()吞下了这些错误(然而我可以重新抛出这些错误来触发GlobalErrorHandlerService)

因此,我们的目标必须是重构MainInterceptorService,使其不会将原始错误类型转换为不同类型的对象。可以这样做:

export class MainInterceptorService implements HttpInterceptor {
constructor() { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// req=req.clone({headers:req.headers.set("Auth","Bearer"+token)})
return next.handle(req).pipe(
catchError(
(err: HttpErrorResponse|Error)=>{
if (err instanceof HttpErrorResponse){
console.error('Server side error'+err);
} else {
console.error('Not a httpErrorResponse'+err);
}
return throwError(() => err);
}
)
);
}
}

重要:

  • 您实际上可以忘记我在之前的回答中提出的代码建议。除了上面显示的MainInterceptorService代码外,所有内容保持原样即可。
  • 请注意,客户端错误可能不会进入HttpInterceptor,因为它们通常与http请求无关。
  • 你基本上使用ErrorHandler来处理客户端错误,HttpInterceptors来处理与http请求相关的错误。
  • 在下面的链接下,你可以找到一个关于错误相关的HttpInterceptor的例子:在ngrx效果中实现catchError后,全局ErrorHandler不工作

最新更新