NestJS 异常过滤器不应该捕获事件发射器错误吗?

发布于 2025-01-11 08:42:23 字数 2319 浏览 0 评论 0原文

我正在重构的 NestJS 应用程序上运行一些手动测试,并且刚刚从 Nest 的全局异常过滤器中发现了奇怪的行为。 创建该项目的开发人员将其用作异常过滤器:


import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  HttpStatus,
} from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';
import { LoggerService } from '../../config/logger.service';

@Catch()
export class GlobalExceptionsFilter implements ExceptionFilter {
  constructor(
    private readonly httpAdapterHost: HttpAdapterHost,
    private readonly logger: LoggerService,
  ) {}

  catch(exception: Error, host: ArgumentsHost): void {
    const { httpAdapter } = this.httpAdapterHost;

    const ctx = host.switchToHttp();

    const httpStatus =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    const responseBody = {
      statusCode: httpStatus,
      path: httpAdapter.getRequestUrl(ctx.getRequest()),
      cause: `${exception.name}: ${exception.message}`,
      timestamp: new Date().toISOString(),
    };

    this.logger.error(responseBody?.cause);

    httpAdapter.reply(ctx.getResponse(), responseBody, httpStatus);
  }
}

这与 中的 catch-everything 过滤器示例几乎完全相同Nest 的文档,所以它确实非常通用。

在该项目的某个部分中,有一个控制器具有如下内容:

  @OnEvent(Events.POTATO_EVENT)
  async potatoMethod(payload) {
    return await this.service.potatoMethod(payload);

当前,服务的 potatoMethod 上没有有效负载验证,因此控制器使用 EventEmitter2 从另一个服务接收有效负载code> 并将其转发到其服务,然后该服务尝试通过调用 ORM 方法来获取数据库中的记录。 如果 payload.potatoNumber 发送正确,不会发生任何错误,但是如果我将 payload.potatoNumber 发送为未定义,ORM 将抛出一个错误,该错误不会被该全局捕获筛选。 如果我不使用 @OnEvent() 而直接在控制器上使用 @Get() 将其转换为端点,则不会发生同样的事情。

目前,main 看起来像这样:

(async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
})();

我可能完全错了,但只有当应用程序未在其 main 上使用 NestFactory.createMicroservice() 时,才会发生这种情况.ts 文件,对吗?如果是肯定的,微服务在 Nest 中到底是如何工作的?

I'm running some manual tests on a NestJS application I'm refactoring and just found an odd behaviour from nest's global exception filter.
The developer who created this project used this as a exception filter:


import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  HttpStatus,
} from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';
import { LoggerService } from '../../config/logger.service';

@Catch()
export class GlobalExceptionsFilter implements ExceptionFilter {
  constructor(
    private readonly httpAdapterHost: HttpAdapterHost,
    private readonly logger: LoggerService,
  ) {}

  catch(exception: Error, host: ArgumentsHost): void {
    const { httpAdapter } = this.httpAdapterHost;

    const ctx = host.switchToHttp();

    const httpStatus =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    const responseBody = {
      statusCode: httpStatus,
      path: httpAdapter.getRequestUrl(ctx.getRequest()),
      cause: `${exception.name}: ${exception.message}`,
      timestamp: new Date().toISOString(),
    };

    this.logger.error(responseBody?.cause);

    httpAdapter.reply(ctx.getResponse(), responseBody, httpStatus);
  }
}

Which is almost exactly the same catch-everything filter example in Nest's docs, so it's very generic, indeed.

In a certain part of this project, there's a controller with something like this:

  @OnEvent(Events.POTATO_EVENT)
  async potatoMethod(payload) {
    return await this.service.potatoMethod(payload);

Currently, there's no payload validation on the service's potatoMethod, so the controller receives a payload from another service using EventEmitter2 and forwards it to it's service, which then tries to fetch a record on the database by calling an ORM method.
If payload.potatoNumber is sent correctly, nothing wrong happens, but if I send payload.potatoNumber as undefined, the ORM will throw an error that will not be caught on that global filter.
The same thing doesn't happen if instead of using a @OnEvent() I just use a @Get() directly on the controller to turn it into an endpoint.

Currently, main looks something like this:

(async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
})();

I might be completely wrong, but this should only happen if the application is not using NestFactory.createMicroservice() on it's main.ts file, right? If positive, how exactly does microservices work natively in Nest?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

三生路 2025-01-18 08:42:23

我对 nestjs 事件发射器 1.4.1 中的这种行为也感到有点措手不及,但同时它的发生也是有道理的,除非您自己处理这些异常。

但他们最终在 https://github.com/nestjs/ 中添加了这种类型的处理event-emitter/pull/908,因此您只需更新到事件发射器 2.0.1 或更高版本(在本答案时为 2.0.4)。

I was also caught a bit off guard with this behaviour in nestjs event emitter 1.4.1, but at the same time it makes sense it happens unless you handle those exceptions yourself.

But they ended up adding that type of handling in https://github.com/nestjs/event-emitter/pull/908, so you just need to update to event emitter 2.0.1 or greater (2.0.4 at the time of this answer).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文