如何在NestJS中使用Multer限制上传文件的总大小?
限制多文件上传总大小的最佳实践
针对NestJS中使用Multer处理多文件上传时的总大小限制需求,这里提供两种实用方案,可根据你的业务场景选择:
方案一:上传过程中实时拦截(推荐用于大文件场景)
这种方式会在文件上传的数据流中实时累加总大小,一旦超过限制立刻中断上传,避免浪费服务器带宽和存储资源。
步骤1:自定义总大小限制的拦截器
创建继承自AnyFilesInterceptor的自定义拦截器,通过监听文件数据流跟踪总大小:
import { Injectable } from '@nestjs/common'; import { AnyFilesInterceptor } from '@nestjs/platform-express'; import { MulterOptions } from '@nestjs/platform-express/multer/interfaces/multer-options.interface'; import * as multer from 'multer'; @Injectable() export class TotalSizeLimitedFilesInterceptor extends AnyFilesInterceptor { private totalUploadedSize = 0; private readonly maxTotalSize: number; constructor(options: MulterOptions & { maxTotalSize: number }) { super(options); this.maxTotalSize = options.maxTotalSize; this.setupSizeLimitStorage(); } private setupSizeLimitStorage() { const originalStorage = this.options.storage || multer.diskStorage({}); this.options.storage = { _handleFile: (req, file, callback) => { // 监听文件数据流的chunk,累加总大小 file.stream.on('data', (chunk) => { this.totalUploadedSize += chunk.length; if (this.totalUploadedSize > this.maxTotalSize) { const error = new Error(`总文件大小超过限制:${this.maxTotalSize / (1024 * 1024)}MB`); file.stream.destroy(error); callback(error, null); } }); // 用原始storage处理文件存储 originalStorage._handleFile(req, file, callback); }, _removeFile: (req, file, callback) => { originalStorage._removeFile(req, file, callback); } }; } }
步骤2:在控制器中使用自定义拦截器
替换原有的AnyFilesInterceptor,添加总大小限制配置:
@Post('send') @UseInterceptors( TotalSizeLimitedFilesInterceptor({ limits: { fileSize: 2 * 1024 * 1024 }, // 单个文件最大2MB maxTotalSize: 10 * 1024 * 1024, // 总文件大小最大10MB }), ) sendEmailWithAttachment( @Body() sendEmailPayload: SendEmailPayload, @UploadedFiles() files: Array<Express.Multer.File>, ) { // 你的业务逻辑 }
方案二:上传完成后检查(适合小文件场景)
如果应用主要处理小文件,对资源消耗不敏感,可以在控制器方法中直接计算所有文件的总大小,超过限制则抛出错误并清理已上传文件:
import { BadRequestException } from '@nestjs/common'; import * as fs from 'fs'; @Post('send') @UseInterceptors( AnyFilesInterceptor({ limits: { fileSize: 2 * 1024 * 1024 } }), ) sendEmailWithAttachment( @Body() sendEmailPayload: SendEmailPayload, @UploadedFiles() files: Array<Express.Multer.File>, ) { const MAX_TOTAL_SIZE = 10 * 1024 * 1024; // 总大小限制10MB const totalSize = files.reduce((sum, file) => sum + file.size, 0); if (totalSize > MAX_TOTAL_SIZE) { // 清理已上传的文件 files.forEach(file => fs.unlinkSync(file.path)); throw new BadRequestException(`总文件大小超过${MAX_TOTAL_SIZE / (1024 * 1024)}MB限制`); } // 后续业务逻辑 }
补充:错误处理优化
可以注册一个Multer异常过滤器,统一处理上传错误,返回友好提示:
import { ExceptionFilter, Catch, ArgumentsHost, BadRequestException } from '@nestjs/common'; import { MulterError } from 'multer'; @Catch(MulterError) export class MulterExceptionFilter implements ExceptionFilter { catch(exception: MulterError, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); let message = '文件上传失败'; if (exception.code === 'LIMIT_FILE_SIZE') { message = '单个文件大小超过限制'; } else if (exception.message.includes('总文件大小')) { message = exception.message; } response.status(400).json({ statusCode: 400, message, error: '请求参数错误' }); } }
在控制器上添加@UseFilters(MulterExceptionFilter)即可生效,也可以全局注册该过滤器。
内容的提问来源于stack exchange,提问作者ahbyz
相关产品推荐
相关产品推荐

