WEBKT

NestJS 过滤器实战:从入门到精通,打造高效日志处理流

38 0 0 0

前言:为什么我们需要过滤器?

核心概念:NestJS 过滤器的基本原理

实战演练:构建自定义过滤器

1. 创建过滤器类

2. 使用过滤器

3. 扩展过滤器功能

进阶应用:结合日志库和监控平台

1. 集成 Winston 日志库

2. 集成 Sentry 监控平台

总结:过滤器,你值得拥有!

前言:为什么我们需要过滤器?

兄弟们,咱们在开发过程中,是不是经常遇到各种各样的异常情况?接口请求失败、数据库连接超时、第三方服务挂掉……这些问题,如果不妥善处理,轻则影响用户体验,重则导致整个系统崩溃。而 NestJS 的过滤器(Filters),就是咱们处理这些异常的“救火队员”。

想象一下,你正在开发一个电商网站,用户下单时,突然数据库连接断开了。如果没有过滤器,你可能需要在每个涉及到数据库操作的地方,都写上一大堆 try...catch 代码,不仅代码冗余,而且容易遗漏。有了过滤器,你就可以在一个地方集中处理所有数据库相关的异常,代码更简洁,也更易于维护。

更重要的是,过滤器可以帮助我们更好地记录和分析日志。通过捕获异常信息,我们可以更清晰地了解系统运行状况,更快地定位和解决问题。这对于咱们技术团队来说,简直就是“排雷神器”啊!

核心概念:NestJS 过滤器的基本原理

NestJS 的过滤器,本质上就是一个类,它实现了 ExceptionFilter 接口。这个接口定义了一个 catch 方法,用于捕获和处理异常。当 NestJS 应用抛出异常时,过滤器就会自动“接管”,执行 catch 方法中的逻辑。

import { Catch, ExceptionFilter, ArgumentsHost, HttpException } from '@nestjs/common';
@Catch(HttpException) // 指定捕获的异常类型
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception.getStatus();
response
.status(status)
.json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
message: exception.message
});
}
}

上面这段代码,就是一个简单的 HTTP 异常过滤器。它捕获所有 HttpException 类型的异常,并将异常信息以 JSON 格式返回给客户端。咱们可以看到,catch 方法接收两个参数:

  • exception: 当前捕获的异常对象。
  • host: 一个 ArgumentsHost 对象,它提供了访问请求和响应对象的方法。

通过 host.switchToHttp(),我们可以获取到 HTTP 请求的上下文,进而获取请求和响应对象。然后,我们就可以根据异常信息,自定义响应内容。

实战演练:构建自定义过滤器

了解了基本原理,咱们就可以动手构建自己的过滤器了。下面,我将带大家一步步实现一个更强大的自定义过滤器,它可以处理各种类型的异常,并提供更详细的日志记录。

1. 创建过滤器类

首先,创建一个名为 all-exceptions.filter.ts 的文件,并添加以下代码:

import { Catch, ExceptionFilter, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
import { Logger } from '@nestjs/common';
@Catch() // 不指定异常类型,捕获所有异常
export class AllExceptionsFilter implements ExceptionFilter {
private readonly logger = new Logger(AllExceptionsFilter.name);
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
const message = exception instanceof HttpException
? exception.message
: 'Internal server error';
this.logger.error(`[${request.method}] ${request.url} - ${status} - ${message}`);
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
message: message,
});
}
}

在这个过滤器中,我们做了一些改进:

  • @Catch() 不指定异常类型,表示捕获所有类型的异常。
  • 引入了 Logger,用于记录异常日志。
  • 判断异常类型,如果是 HttpException,则获取其状态码和消息;否则,统一返回 500 状态码和 “Internal server error” 消息。
  • 记录详细的日志信息,包括请求方法、URL、状态码和错误消息。

2. 使用过滤器

创建好过滤器后,我们需要将其应用到 NestJS 应用中。有三种方式可以应用过滤器:

  • 全局范围:main.ts 文件中,使用 app.useGlobalFilters() 方法。

    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    import { AllExceptionsFilter } from './all-exceptions.filter';
    async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    app.useGlobalFilters(new AllExceptionsFilter()); // 应用全局过滤器
    await app.listen(3000);
    }
    bootstrap();
  • 控制器范围: 在控制器类上使用 @UseFilters() 装饰器。

    import { Controller, Get, UseFilters } from '@nestjs/common';
    import { AllExceptionsFilter } from './all-exceptions.filter';
    @Controller('cats')
    @UseFilters(AllExceptionsFilter) // 应用控制器范围过滤器
    export class CatsController {
    @Get()
    findAll() {
    throw new Error('This is a test error');
    }
    }
  • 方法范围: 在控制器方法上使用 @UseFilters() 装饰器。

    import { Controller, Get, UseFilters } from '@nestjs/common';
    import { AllExceptionsFilter } from './all-exceptions.filter';
    @Controller('cats')
    export class CatsController {
    @Get()
    @UseFilters(AllExceptionsFilter) // 应用方法范围过滤器
    findAll() {
    throw new Error('This is a test error');
    }
    }

根据实际需求,选择合适的应用范围。一般来说,全局范围的过滤器适用于处理所有未捕获的异常,而控制器或方法范围的过滤器适用于处理特定模块或接口的异常。

3. 扩展过滤器功能

咱们的自定义过滤器已经具备了基本的功能,但还可以进一步扩展,以满足更复杂的需求。例如:

  • 自定义日志格式: 可以根据需要,自定义日志的格式,例如添加请求 ID、用户 ID 等信息。
  • 异常分类: 可以根据异常类型,将异常分为不同的类别,例如数据库异常、网络异常、业务异常等,并分别处理。
  • 异常通知: 可以将异常信息发送到邮件、短信、Slack 等渠道,及时通知相关人员。
  • 异常重试: 对于某些可恢复的异常,可以尝试自动重试。

进阶应用:结合日志库和监控平台

为了更好地管理和分析日志,我们可以将 NestJS 的过滤器与第三方日志库和监控平台结合使用。

1. 集成 Winston 日志库

Winston 是一个流行的 Node.js 日志库,它提供了丰富的功能,例如多级别日志、多种日志输出方式(控制台、文件、数据库等)、自定义日志格式等。

首先,安装 Winston:

npm install winston

然后,修改 all-exceptions.filter.ts 文件,使用 Winston 记录日志:

import { Catch, ExceptionFilter, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
import * as winston from 'winston';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
private readonly logger = winston.createLogger({
level: 'error', // 设置日志级别
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
), // 设置日志格式
transports: [
new winston.transports.Console(), // 输出到控制台
new winston.transports.File({ filename: 'error.log' }), // 输出到文件
],
});
catch(exception: unknown, host: ArgumentsHost) {
// ... 其他代码 ...
this.logger.error({
method: request.method,
url: request.url,
status: status,
message: message,
stack: exception instanceof Error ? exception.stack : null,
});
// ... 其他代码 ...
}
}

在这个例子中,我们创建了一个 Winston logger,设置日志级别为 error,日志格式为 JSON,并将日志输出到控制台和 error.log 文件。

2. 集成 Sentry 监控平台

Sentry 是一个流行的错误跟踪和监控平台,它可以帮助我们实时监控应用的异常情况,并提供详细的错误报告、性能分析等功能。

首先,在 Sentry 官网注册账号并创建一个项目,获取 DSN(Data Source Name)。

然后,安装 Sentry 的 NestJS SDK:

npm install @sentry/node @sentry/tracing

接着,在 main.ts 文件中初始化 Sentry:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AllExceptionsFilter } from './all-exceptions.filter';
import * as Sentry from '@sentry/node';
import * as Tracing from '@sentry/tracing';
async function bootstrap() {
Sentry.init({
dsn: 'YOUR_SENTRY_DSN', // 替换为你的 DSN
integrations: [
new Sentry.Integrations.Http({ tracing: true }),
new Tracing.Integrations.Express({}),
],
tracesSampleRate: 1.0,
});
const app = await NestFactory.create(AppModule);
app.use(Sentry.Handlers.requestHandler());
app.use(Sentry.Handlers.tracingHandler());
app.useGlobalFilters(new AllExceptionsFilter());
app.use(Sentry.Handlers.errorHandler());
await app.listen(3000);
}
bootstrap();

最后,修改 all-exceptions.filter.ts 文件,将异常信息发送到 Sentry:

import { Catch, ExceptionFilter, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
import * as Sentry from '@sentry/node';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
// ... 其他代码 ...
Sentry.captureException(exception); // 发送异常到 Sentry
// ... 其他代码 ...
}
}

现在,当应用发生异常时,Sentry 就会自动捕获并记录异常信息,你可以在 Sentry 平台上查看详细的错误报告和性能分析。

总结:过滤器,你值得拥有!

兄弟们,NestJS 的过滤器,是不是很强大?通过合理使用过滤器,我们可以更好地处理异常、记录日志、监控应用,从而提高系统的稳定性和可靠性。希望这篇文章能帮助大家更好地理解和使用 NestJS 过滤器,打造更健壮的应用!

如果你还有其他关于 NestJS 的问题,欢迎随时交流!

全栈老司机 NestJS过滤器日志处理

评论点评

打赏赞助
sponsor

感谢您的支持让我们更好的前行

分享

QRcode

https://www.webkt.com/article/7867