Nestjs 中,使用基于 HttpException 定义过滤器的话,只能捕获 Http 带状态码(statusCode)的 Exception,不能捕获 throw new Error(‘xxx’) 抛出的错误。
以下是使用实现 ExceptionFilter 接口定义的一个不特定于平台(express 或 fastify,即无论使用这两个web服务框架的其中一个都可以)的,可以捕获所有错误(Error)和异常(Exception)的全局错误/异常过滤器。
1、在项目的根目录的 config 目录 下创建 all-exceptions.filter.ts 文件,内容如下:
// all-exceptions.filter.ts
/**
* 定义捕获所有异常(Exception)和 错误(Error)
* 的全局异常/错误过滤器,需在 app.module.ts 中注册该过滤器
*/
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus } from "@nestjs/common";
import { HttpAdapterHost } from "@nestjs/core";
import { Request, Response } from "express";
// 导入格式化日期时间的第三方工具包
import * as dayjs from 'dayjs';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
constructor(private readonly httpAdapterHost: HttpAdapterHost) { }
catch(exception: any, host: ArgumentsHost) {
console.log('AllExceptionsFilter exception:', exception);
const { httpAdapter } = this.httpAdapterHost;
const ctx = host.switchToHttp();
const request = ctx.getRequest<Request>();
const response = ctx.getResponse<Response>();
const statusCode = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;
const resContents = {
status: statusCode,
cause: exception?.cause,
errName: exception?.name,
message: exception?.message,
time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
// stack: exception?.stack,
path: httpAdapter.getRequestUrl(request),
}
// 使用不特定于平台(express 或 fastify)的方式(httpAdapter)返回响应内容
httpAdapter.reply(response, resContents, statusCode);
}
}
2、把以上定义的注册为全局的错误/异常过滤器
2.1、方法一:在 main.ts 中注册为全局的错误/异常过滤(此方式不支持依赖注入)
// main.ts
...
import { AllExceptionsFilter } from './common/all-exceptions.filter.ts';
...
app.useGlobalFilters(new AllExceptionsFilter());
...
2.2、方法二(推荐):在 app.module.ts 中的 @Module 装饰器中的 providers 节点作为提供器注入
// app.module.ts
...
import { AllExceptionsFilter } from './common/all-exceptions.filter.ts';
...
@Module({
...
providers: [
{
provide: 'APP_FILTER',
useClass: AllExceptionsFilter
}
],
...
})