Exception Filter 在 Nest 应用抛异常时,捕获它并返回
比如
新建项目
nest new exception-filter-demo
自己定义个 exception filter
@Catch 指定要捕获的异常,这里指定 BadRequestException
import {
ArgumentsHost,
BadRequestException,
Catch,
ExceptionFilter,
} from '@nestjs/common';
@Catch(BadRequestException)
export class HelloFilter implements ExceptionFilter {
catch(exception: BadRequestException, host: ArgumentsHost) {
debugger;
}
}
hello.filter.ts 更新
import {
ArgumentsHost,
BadRequestException,
Catch,
ExceptionFilter,
HttpException,
} from '@nestjs/common';
import { Response } from 'express';
@Catch(BadRequestException)
export class HelloFilter implements ExceptionFilter {
catch(exception: BadRequestException, host: ArgumentsHost) {
const http = host.switchToHttp();
const response = http.getResponse<Response>();
const statusCode = exception.getStatus();
response.status(statusCode).json({
code: statusCode,
message: exception.message,
error: 'Bad Request',
addOthers: 222,
});
}
}
但其实这也有个问题。
当我们用 ValidationPipe 时
比如加一个路由
@Post('aaa')
aaa(@Body() aaaDto: AaaDto ){
return 'success';
}
添加 src/aaa.dto.ts
export class AaaDto {
aaa: string;
bbb: number;
}
安装
npm install --save class-validator class-transformer
更新 src/aaa.dto.ts
import { IsEmail, IsNotEmpty, IsNumber } from 'class-validator';
export class AaaDto {
@IsNotEmpty({ message: 'aaa 不能为空' })
@IsEmail({}, { message: 'aaa 不是邮箱格式' })
aaa: string;
@IsNumber({}, { message: 'bbb 不是数字' })
@IsNotEmpty({ message: 'bbb 不能为空' })
bbb: number;
}
使用
这个是 filter 的
打断点先看下
根据结构 更新内容
import { ArgumentsHost, BadRequestException, Catch, ExceptionFilter, HttpException } from '@nestjs/common';
import { Response } from 'express';
@Catch(HttpException)
export class HelloFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const http = host.switchToHttp();
const response = http.getResponse<Response>();
const statusCode = exception.getStatus();
const res = exception.getResponse() as { message: string[] };
response.status(statusCode).json({
code: statusCode,
message: res?.message?.join ? res?.message?.join(',') : exception.message,
error: 'Bad Request',
xxx: 111
})
}
}
nice!
现在,ValidationPipe 的错误和其他的错误就都返回了正确的格式
想在 Filter 里注入 AppService 怎么做?
其余的全局 Guard、Interceptor、Pipe 也是这样注册
Nest 会把所有 token 为 APP_FILTER 的 provider 注册为全局 Exception Filter
比如我注入了 AppService,然后调用它的 getHello 方法
hello.filter.ts
import {
ArgumentsHost,
BadRequestException,
Catch,
ExceptionFilter,
HttpException,
Inject,
} from '@nestjs/common';
import { Response } from 'express';
import { AppService } from './app.service';
@Catch(HttpException)
export class HelloFilter implements ExceptionFilter {
@Inject(AppService)
private readonly appService: AppService;
catch(exception: HttpException, host: ArgumentsHost) {
const http = host.switchToHttp();
const response = http.getResponse<Response>();
const statusCode = exception.getStatus();
const res = exception.getResponse() as { message: string[] };
response.status(statusCode).json({
code: statusCode,
message: res?.message?.join ? res?.message?.join(',') : exception.message,
error: 'Bad Request',
xxx: 111,
yyy: this.appService.getHello(),
});
}
}
自定义 Exception 也是可以的
比如添加一个 src/unlogin.filter.ts
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpStatus,
} from '@nestjs/common';
import { Response } from 'express';
export class UnLoginException {
message: string;
constructor(message?) {
this.message = message;
}
}
@Catch(UnLoginException)
export class UnloginFilter implements ExceptionFilter {
catch(exception: UnLoginException, host: ArgumentsHost) {
const response = host.switchToHttp().getResponse<Response>();
response
.status(HttpStatus.UNAUTHORIZED)
.json({
code: HttpStatus.UNAUTHORIZED,
message: 'fail 用户未登录',
data: exception.message || '用户未登录',
})
.end();
}
}
创建了一个 UnloginException 的异常。
然后在 ExceptionFilter 里 @Catch 了它。
在 AppModule 里注册这个全局 Filter
在 AppController 里抛出这个异常