You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

抛出HttpException后NestJS服务崩溃问题求助

环境信息

// package.json
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/typeorm": "^10.0.1",
// 系统
Mac m1
// Dockerfile
FROM node:21
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
EXPOSE 3000
CMD npm run start:dev

我配置了全局异常过滤器HttpExceptionFilter,但抛出HttpException后服务直接停止工作,后续所有请求都返回Error: read ECONNRESET,Docker控制台不再接收请求。

代码情况

  • 全局过滤器配置(main.ts):
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.setGlobalPrefix('api');
  app.useGlobalFilters(new HttpExceptionFilter());
  await app.listen(3000);
}
bootstrap();
  • 异常过滤器实现:
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    console.log('filter');
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    response.status(status).json({
      statusCode: status,
      message: exception.message,
      timestamp: new Date().toISOString(),
      path: request.url,
    });
  }
}
  • 业务代码:
    StudiesService中的getStudyById和deleteStudyById方法,在数据不存在时会抛出NotFoundException或HttpException;StudiesController中GET /:id返回Promise,DELETE /:id未返回Promise。

问题现象

  • 正常请求(如GET localhost:3000/api/studies/2)可收到正确响应;
  • 发送DELETE localhost:3000/api/studies/100(ID不存在)触发异常时,Docker控制台打印异常栈,服务崩溃;
  • 后续任何请求都返回Error: read ECONNRESET;
  • 特殊情况:GET请求触发异常时,过滤器正常工作,服务不会崩溃。

问题求助

为何DELETE请求触发异常会导致服务崩溃,如何解决?


原因分析

问题核心在于DELETE /:id的控制器方法未返回Promise。NestJS中,异步控制器方法如果不返回Promise,内部抛出的异常无法被Nest正确捕获并传递给异常过滤器,最终会触发未处理的Promise拒绝,导致Node.js进程直接崩溃(Node.js默认会终止存在未处理Promise拒绝的进程)。

而GET方法返回了Promise,Nest能完整追踪异步流程,异常会被正常传递给全局过滤器处理,因此不会引发服务崩溃。

解决方法

修改StudiesController中的DELETE /:id方法,确保它返回Promise:

示例修改

假设原代码是:

@Delete(':id')
deleteStudyById(@Param('id') id: string) {
  this.studiesService.deleteStudyById(id);
}

改成:

@Delete(':id')
async deleteStudyById(@Param('id') id: string) {
  return this.studiesService.deleteStudyById(id);
}

或者手动封装Promise返回:

@Delete(':id')
deleteStudyById(@Param('id') id: string) {
  return Promise.resolve(this.studiesService.deleteStudyById(id));
}

这样Nest就能正确捕获异步操作中的异常,交给全局过滤器处理,避免服务崩溃。

额外防护(可选)

为了避免其他未处理的Promise拒绝导致服务崩溃,可以在项目入口添加全局监听:

async function bootstrap() {
  // ... 现有代码
  process.on('unhandledRejection', (reason, promise) => {
    console.error('未处理的Promise拒绝:', reason);
    // 可添加日志上报等逻辑,但核心还是要确保所有异步控制器方法返回Promise
  });
}
bootstrap();

内容的提问来源于stack exchange,提问作者nayounsang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 20:51:06