說起Nestjs的異常過濾器,不能不提.Net的全局過濾器Filter,功能那是相當的強悍,用理論話說叫AOP 面向切面編程,可謂方便了太多需要異常處理的場景。說回Nestjs的異常過濾器,實現類似的功能,采用相似的處理方式,只不過一個面向C#,一個面向Nodejs,很榮幸的我,在兩個框架都找到了類似的東西。
面向切面編程AOP,是一種類似于編程規范的東東,同門師兄弟有叫面向接口編程、SOLID原則等等。
Nestjs的異常處理
默認異常處理
Nestjs內置了默認的全局異常過濾器,處理能夠轉換成Httpexception的異常。
如果是Httpexception或其子類異常,那么會返回該異常的JSON格式:
1
|
{ "exceptionCode" :40005, "message" : "自定義異常" , "path" : "/" } |
如果不是Httpexception或其子類異常,那么會返回:
1
|
{ "statusCode" :500, "message" : "Internal server error" } |
由于Nestjs采用了內置的默認異常處理,因此不會出現由于出現未捕獲的異常導致程序崩潰。
自定義異常過濾器處理
由于內置異常處理返回值格式無法調整,因此自定義異常就顯得又為正常。自定義異常可以使返回異常信息自定義,且可以增加自定義異常編碼,方便客戶端人員根據異常編碼進行不同的展示。
如何自定義異常?
不重復造輪子是程序員的自我約束,首先我們新建我們自己的異常基類:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
import { HttpException } from "@nestjs/common" ; /** * 定義基礎異常類 * * @export * @class BaseException * @extends {HttpException} */ export class BaseException extends HttpException { /** * Creates an instance of BaseException. * @param {number} exceptionCode 自定義異常編號 * @param {string} errorMessage 提示信息 * @param {number} statusCode 狀態碼 * @memberof BaseException */ constructor(public exceptionCode: number, public errorMessage: string, public statusCode: number) { super ({ exceptionCode: exceptionCode, errorMessage: errorMessage }, statusCode); } /** * 獲取自定義異常代碼 * * @return {*} * @memberof BaseException */ getExceptionCode(): number { return this .exceptionCode; } getErrorMessage(): string { return this .errorMessage; } getStatusCode(): number { return this .statusCode; } } |
然后我們新建一個未授權異常類型,其中增加了自定義異常代碼:
1
2
3
4
5
6
7
8
|
import { HttpStatus } from "@nestjs/common" ; import { BaseException } from "./base.exception" ; export class UnCauhtException extends BaseException { constructor() { super (40000, "系統運行異常,請聯系管理員!" , HttpStatus.FORBIDDEN); } } |
建立好了自定義異常,那么我們就需要處理未授權異常,首先新建自定義異常處理基類,請注意 此處我們使用的事Express:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
import { ArgumentsHost, ExceptionFilter, HttpException } from "@nestjs/common" ; import { HttpArgumentsHost } from "@nestjs/common/interfaces" ; import { BaseException } from "src/exceptions/base.exception" ; import { Response, Request } from "express" ; /** * 異常基礎類過濾器 * * @export * @class BaseExceptionFilter * @implements {ExceptionFilter<BaseException>} */ export abstract class BaseExceptionFilter implements ExceptionFilter<BaseException> { /** * 異常類捕獲 * * @abstract * @param {BaseException} exception * @param {ArgumentsHost} host * @memberof BaseExceptionFilter */ abstract catch (exception: BaseException, host: ArgumentsHost); /** * 獲取http請求上下文參數 * * @protected * @param {ArgumentsHost} host * @return {*} * @memberof BaseExceptionFilter */ protected getHttpContext(host: ArgumentsHost) { return host.switchToHttp(); } /** * 獲取http 響應參數 * * @protected * @param {HttpArgumentsHost} httpContext * @return {*} * @memberof BaseExceptionFilter */ protected getResponse(httpContext: HttpArgumentsHost): Response { return httpContext.getResponse<Response>(); } /** * 獲取http請求參數 * * @protected * @param {HttpArgumentsHost} httpContext * @return {*} * @memberof BaseExceptionFilter */ protected getRequest(httpContext: HttpArgumentsHost): Request { return httpContext.getRequest<Request>(); } /** * 寫入異常信息到客戶端 * * @param {ArgumentsHost} host * @param {BaseException} exception * @memberof BaseExceptionFilter */ protected writeToClient(host: ArgumentsHost, exception: BaseException) { const ctx = this .getHttpContext(host); if (exception instanceof BaseException){ this .getResponse(ctx).status(exception.statusCode).json({ exceptionCode: exception.getExceptionCode(), message: exception.getErrorMessage(), path: this .getRequest(ctx).url }); } else { const httpException=exception ; this .getResponse(ctx).status(500).json({ message: "未處理的異常" , path: this .getRequest(ctx).url }); } } } |
新建未授權異常處理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import { ArgumentsHost, Catch } from "@nestjs/common" ; import { AuthException } from "src/exceptions/auth.exception" ; import { BaseException } from "src/exceptions/base.exception" ; import { BaseExceptionFilter } from "./base.exception.filter" ; @Catch(AuthException) export class AuthExceptionFilter extends BaseExceptionFilter { constructor(){ super (); console.log( "授權異常構造函數初始化" + new Date().toISOString()); } catch (exception: AuthException, host: ArgumentsHost) { exception.exceptionCode=40002; console.log( "授權異常執行" + new Date().toISOString()); this .writeToClient(host,exception); } } |
針對未授權異常處理類,進行幾點說明:
- 增加了Catch注解,只捕獲Authexception的異常,其他類型的異常此類不進行處理
- 繼承自定義異常處理類Baseexceptionfilter
應用范圍
異常處理類可應用于method、controller、全局,甚至同一個Controller可以定義多個自定義異常類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
import { Controller, ForbiddenException, Get, HttpException, HttpStatus, UseFilters } from '@nestjs/common' ; import { AppService } from './app.service' ; import { AuthException } from './exceptions/auth.exception' ; import { BusinessException } from './exceptions/business.exception' ; import { UnCauhtException } from './exceptions/uncauht.exception' ; import { AuthExceptionFilter } from './filters/auth.exception.filter' ; import { BusinessExceptionFilter } from './filters/business.exception.filter' ; /** * 帶有單個路由的基本控制器示例ff */ @UseFilters(AuthExceptionFilter,BusinessExceptionFilter) @Controller() export class AppController { constructor(private readonly appService: AppService) {} @Get() getHello(): string { //throw new Error("666"); throw new BusinessException( "自定義異常" ,HttpStatus.OK); throw new AuthException(); throw new HttpException( "自定義異常" ,HttpStatus.FORBIDDEN); return this .appService.getHello(); } @Get( "name" ) getName():string { return "guozhiqi" ; } } |
幾點說明:
- 我們使用Usefilters注解進行異常過濾器的添加
- 我們在Appcontroller中定義了兩種不同類型的自定義異常處理類
- 也就是我們Appcontroller中拋出的異常,只要是我們定義的這兩種,那么都可以被正常處理。
幾點疑問
Usefitlers中我們自定義的異常處理類會初始化幾次?
答案:我們通過類型注冊到Appcontroller的自定義異常類只會在程序初始化的時候初始化一次。也就是說程序啟動之后,每個
controller、每個method定義了哪些異常處理類都已經確定。
如果我們捕獲到異常,但不進行任何處理,會發生什么?
答案:如果我們的異常處理方法什么也不做,那么恭喜你,會成功的將瀏覽器請求hang死,因為異常未處理,那么瀏覽器會一直得不到響應。
多個異常之間的處理順序如何?
答案:如果多個異常處理均可以捕獲到該異常,那么只有第一個有效,也就是說異常處理類和 中間件不同,異常處理類只能其中一個處理,而中間件需要都進行處理。
Nestjs的@Usefilters 像誰?
首先從JS角度來看,像Angular,如果往后端看,最像Spring。
Nestjs的異常處理并不復雜,復雜的是需要我們針對不同類型的異常進行處理,提取異常的共性。
參考文檔:docs.nestjs.cn
到此這篇關于nestjs中異常過濾器Exceptionfilter的具體使用的文章就介紹到這了,更多相關nest 異常過濾器Exceptionfilter內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://www.cnblogs.com/jiagoushi/p/14382569.html