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

Nest.js中Multer规则触发异常后连接未释放问题求助

Nest.js文件上传异常后连接未终止导致请求隔次成功问题排查与解决

问题背景

我有一个接收单张或多张图片上传(multipart/form-data)的Nest.js应用。当违反Multer规则(如发送超过1个文件)时,Multer会抛出Too Many Files异常,该异常被全局过滤器捕获,但连接未真正终止,导致再次请求时应用挂起,需等待超时或取消请求后才能正常使用(请求仅隔次成功)。取消注释异常过滤器中的response.destroy语句强制终止连接可解决问题,但担心该方式引发后续隐患。已尝试Nest.js 9.x版本、自定义拦截器、中间件等多种方案,均出现相同问题。

相关代码

控制器代码

@Post()
@UseInterceptors(FilesInterceptor('image')) 
public async initiate( 
  @Res() res: Response, @UploadedFiles() images?: Array<Express.Multer.File>): Promise<void> { 
     let retCode = HttpStatus.ACCEPTED; 
     res.status(retCode).send(); 
} 

MulterModule注册模块代码

@Module({ 
  imports: [ 
     MulterModule.registerAsync({ useClass: MulterConfig }) 
  ],
  controllers: [TestController],
  providers: [Logger, TestService] 
}) 
export class TestModule {}

MulterConfig类代码

@Injectable() 
export class MulterConfig implements MulterOptionsFactory { 
  constructor() {} 
  public createMulterOptions(): MulterModuleOptions { 
    return { 
            limits: { 
                files: 1 
            }, 
            fileFilter: (req, file, callback) => { 
                console.log(`Filetype is: ${file.mimetype}`); 
                if(file.mimetype === 'image/png') { 
                    callback(null, true); 
                } else { 
                    callback(new BadRequestException('asdfasdf'), false); 
                } 
            } 
        } 
    } 
} 

全局异常过滤器注册(main.ts)

app.useGlobalFilters(new TestExceptionFilter());

异常过滤器代码

import { Catch, ExceptionFilter, ArgumentsHost } from "@nestjs/common"; 
import { Request, Response } from 'express';
 

@Catch()

export class TestExceptionFilter implements ExceptionFilter { 
    catch(exception: any, host: ArgumentsHost) { 
       
      console.log('in exception filter');
      let status = 500;
    
      const ctx = host.switchToHttp();
 
      const response = ctx.getResponse<Response>();

      response.status(status).send();

      //response.destroy(new Error('forcing stream destruction')); 
    } 
} 

项目依赖版本

"@nestjs/axios": "^3.0.0",
    "@nestjs/common": "^10.0.0",
    "@nestjs/config": "^3.0.0",
    "@nestjs/core": "^10.0.0",
    "@nestjs/mapped-types": "*",
    "@nestjs/mongoose": "^10.0.1",
    "@nestjs/passport": "^10.0.0",
    "@nestjs/platform-express": "^10.0.0",
    "@nestjs/terminus": "^10.0.1",
    "jwks-rsa": "^3.0.1",
    "mongoose": "^7.4.0",
    "nest-winston": "^1.9.3",
    "passport": "^0.6.0",
    "passport-jwt": "^4.0.1",
    "reflect-metadata": "^0.1.13",
    "rxjs": "^7.8.1",
    "winston": "^3.10.0"

问题原因

核心原因是Multer处理multipart/form-data请求时,若中途抛出异常,请求的数据流并未被完全消费。当你在异常过滤器中仅调用response.status(status).send()时,Express会尝试发送响应,但客户端仍在继续上传文件(请求流未被终止),导致连接处于半开状态。Node.js的HTTP连接池无法释放该连接,后续新请求会被阻塞等待可用连接,最终出现请求隔次成功的现象。

合理解决方案

方案1:在异常过滤器中主动终止请求流(推荐)

在异常过滤器中不仅发送错误响应,还要主动销毁请求的底层TCP连接,强制客户端停止上传并释放连接资源:

@Catch()
export class TestExceptionFilter implements ExceptionFilter {
  catch(exception: any, host: ArgumentsHost) {       
    console.log('in exception filter');
    const status = exception instanceof BadRequestException ? 400 : 500;    
    const ctx = host.switchToHttp(); 
    const request = ctx.getRequest<Request>();
    const response = ctx.getResponse<Response>();
    
    // 终止底层TCP连接,阻止客户端继续发送数据
    if (request.socket) {
      request.socket.destroy();
    }
    
    response.status(status).json({
      statusCode: status,
      message: exception.message || 'Internal Server Error'
    });
  } 
}

方案2:在Multer配置中添加onError回调提前处理

直接在Multer的配置里添加异常处理回调,在Multer抛出异常时立即终止连接,避免异常流走到全局过滤器:

@Injectable() 
export class MulterConfig implements MulterOptionsFactory { 
  public createMulterOptions(): MulterModuleOptions { 
    return { 
      limits: { files: 1 }, 
      fileFilter: (req, file, callback) => { 
        console.log(`Filetype is: ${file.mimetype}`); 
        if(file.mimetype === 'image/png') { 
          callback(null, true); 
        } else { 
          callback(new BadRequestException('仅支持PNG格式图片'), false); 
        } 
      },
      onError: (err, req, res, next) => {
        // 直接终止请求连接
        req.socket.destroy();
        next(err);
      }
    }; 
  } 
}

方案3:使用Nest.js默认异常过滤器

如果你不需要自定义全局异常处理逻辑,可以移除自定义的TestExceptionFilter,使用Nest.js内置的异常过滤器。默认过滤器在处理Multer异常时,会自动处理请求流的释放(Nest.js底层已做相关优化)。

效果验证

修改后,当上传不符合规则的文件时,客户端会立即收到错误响应,连接被正常终止,后续请求不会再出现挂起情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 05:14:56