Note
异常过滤器
nestjs的异常过滤器介绍
异常过滤器
NestJs存在内置的异常过滤器 ExceptionFilter ,但是为了满足需要,有时会自定义异常过滤器,如所有错误整理成固定结构,小项目通常用不到。所有异常过滤器都要实现泛型接口 ExceptionFilter<T> 。并且实现 catch(exception: T, host: ArgumentsHost) 方法。T 表示异常的类型。常见的统一过滤器可以:
- 统一错误响应格式。
- 记录未知异常和堆栈。
- 隐藏数据库密码、SQL 等内部信息。
- 增加 requestId、请求路径和时间。
- 把数据库异常转换成业务错误码。
- 区分开发环境与生产环境错误详情。
- 上报日志或监控平台。
定义异常过滤器
http-exception.filter.ts
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
} from "@nestjs/common";
import { Request, Response } from "express";
// @Catch() 就是告诉NestJS "HttpExceptionFilter"是个异常过滤器
// @Catch(HttpException) 告诉 Nest 这个特定过滤器只查找 HttpException 类型的异常。@Catch() 装饰器可接受单个参数或以逗号分隔的列表
// @Catch() 装饰器的参数列表为空,可以捕获每一个未处理的异常(无论异常类型如何)
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
// 获取响应实例
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,
});
}
}
ArgumentsHost
是 NestJS 对当前处理器底层参数的跨平台统一抽象,让过滤器等框架组件能够访问 HTTP、WebSocket 和微服务异常上下文中的真实对象。简单来说就是它获取当前请求环境的异常请求/响应内容
❓为什么不直接把 request 和 response 传进来 因为 NestJS 不只支持普通 HTTP,它还支持其他环境,并且同一个异常过滤器机制可能运行在:HTTP REST 请求、WebSocket、消息RPC / 微服务消息、GraphQL 请求
异常类型的HTTP状态
| 异常 | 最终 HTTP 状态 |
|---|---|
BadRequestException |
400 |
UnauthorizedException |
401 |
ForbiddenException |
403 |
NotFoundException |
404 |
InternalServerErrorException |
500 |
| 未处理的普通 Error | 500 |
HttpException |
所有 NestJS HTTP 异常,包括 400、401、403、404、500 |
DTO 中
class-validator参数校验失败会报 BadRequestException` 异常
常见方法
getType()
获取当前上下文类型,主要用途就是编写跨 HTTP、RPC 和 WebSocket 环境的通用组件
const type = host.getType();
// 普通 NestJS 上下文中常见结果为:http/ws/rpc,即http异常/websocket异常/微服务异常
console.log(type);
switchToHttp()
取得 HTTP 环境的参数访问器,用于获取http环境下的异常上下文
// host: ArgumentsHost
const http = host.switchToHttp();
// 获取请求数据
const request = http.getRequest();
// 获取响应数据
const response = http.getResponse();
// 执行下一个中间件,nestjs中通常不使用
const next = http.getNext();
switchTows()
用于 WebSocket 环境
// host: ArgumentsHost
const ws = host.switchToWs();
// 当前 WebSocket 客户端或连接对象
const client = ws.getClient();
// 客户端发送的数据
const data = ws.getData();
// 当前事件模式或事件名称
const pattern = ws.getPattern();
switchToRpc()
用于 NestJS 微服务或 RPC 上下文
const rpc = host.switchToRpc();
// 消息的 payload
const data = rpc.getData();
// 当前微服务消息对应的传输层上下文对象
const context = rpc.getContext();
getArgs()
直接获取底层的完整参数数组,根据不同的环境获取不同的异常上下文
HTTP 环境下,可以粗略理解成:const [request, response, next] = host.getArgs();
ArgumentsHost 和 ExecutionContext 的区别
ArgumentsHost只关注当前执行环境及其参数,用于异常过滤器。ExecutionContext继承了ArgumentsHost并额外提供getClass(获取当前 Controller 类)和getHandler(获取当前路由),所以ArgumentsHost常用于守卫和拦截器
作用域
根据绑定位置的不同,异常过滤器的作用于不同
方法级
cats.controller.ts
@Post()
// 也可以传入实例@UseFilters(new HttpExceptionFilter()),但是更推荐传入类 ,传入类内存消耗低一些,因为 Nest 可以在整个模块中轻松复用相同类的实例
@UseFilters(HttpExceptionFilter)
async create(@Body() createCatDto: CreateCatDto) {
throw new HttpException();
}
控制器级
仅作用于CatsController的路由
cats.controller.ts
@Controller()
@UseFilters(HttpExceptionFilter)
export class CatsController {}
全局
全局作用域的过滤器,它用于整个应用程序,作用于每个控制器和每个路由处理器。也可通过在任意模块中使用 APP_FILTER + useClass 进行全局注册。
main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 注册全局异常过滤器
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();