-
Exception Filter
的目的是获得对异常层的完全控制权,可以精确控制数据的响应;
- 异常过滤器应实现
ExceptionFilter<T>
接口,它提供了处理方法 catch(exception: T, host: ArgumentsHost)
,其中,T
表示处理的异常类型;
-
@Catch()
:绑定所需的元数据到异常过滤器上,告知异常过滤器捕获的异常类型,支持传入多个参数;
nest g filter xxx //创建过滤器
- 捕获
HttpException
的异常过滤器,通过 response.json()
发送自定义的响应数据;
http-exception.filter.ts
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
//HttpArgumentsHost
const ctx = host.switchToHttp();
//借助Express来返回原生的Express类型化对象
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
//发送响应
response
.status(status)
.json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
- 使用异常过滤器:
@UseFilters()
-
@UseFilters()
可以接收单个过滤器,也可以接收多个过滤器;应尽可能传入类而不是实例,因为Nest可以在整个模块中复用一个类的实例,从而减少内存使用;
- 在处理程序上(控制器方法)
@Post()
@UseFilters(HttpExceptionFilter)
async create(@Body() createCatDto: CreateCatDto) {
throw new ForbiddenException();
}
- 在控制器上,作用于其中的所有方法
@UseFilters(HttpExceptionFilter)
export class CatsController {}
- 设置全局异常过滤器
main.ts
app.useGlobalFilters(new HttpExceptionFilter());
-
useGlobalFilters()
不会为网关和混合应用程序设置过滤器;
- 就依赖注入而言,从模块外部注册的全局过滤器不能注入依赖,因为它不属于任何模块;为此,则在任何模块上去注册:
app.module.ts
import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
@Module({
providers: [{
provide: APP_FILTER,
useClass: HttpExceptionFilter,
}],
})
export class AppModule {}
- 这种注册方式下,任何模块都可以依赖注册异常过滤器对象。
- 为了捕获一切异常,不管是哪个异常类型,也不管异常是否处理,则将装饰器
@Catch()
的参数列表设置为空;
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) { }
}
- 异常过滤器也可以继承,如重用以实现的核心异常过滤器
BaseExceptionFilter
,将异常委托给基础过滤器;
import { BaseExceptionFilter } from '@nestjs/core';
@Catch()
export class AllExceptionsFilter extends BaseExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
super.catch(exception, host);
}
}
- 继承自基础类的过滤器必须由框架本身实例化,不能使用
new
手动创建实例;
- 还可以通过注入
HttpServer
来使用继承自基础类的全局过滤器
main.ts
const { httpAdapter } = app.get(HttpAdapterHost);
app.useGlobalFilters(new AllExceptionsFilter(httpAdapter));