NestJS Multer中间件上传后如何获取自定义新文件名?
问题分析与解决方案
首先,你的代码里有两个核心问题导致拿不到自定义的文件名:
中间件没有真正执行Multer的上传逻辑:你在
resolve方法里只是创建了upload实例并调用了upload.any(),但这个方法返回的是一个中间件函数,你并没有用它去处理当前的req和res,所以你的自定义存储配置根本没生效,req.files还是原始的文件信息。Multer中间件与FilesInterceptor冲突:你同时使用了自定义的Multer中间件和NestJS提供的
FilesInterceptor,这两者都是基于Multer实现的,拦截器会先于中间件处理请求,导致你的中间件配置被覆盖,自然拿不到你设置的文件名。
下面给你两种可行的解决方案:
方案一:直接在FilesInterceptor中配置存储(推荐)
既然你已经在使用NestJS的文件拦截器,完全可以把自定义的存储配置直接传到拦截器里,这样@UploadedFiles()装饰器就能拿到包含新文件名的文件对象:
// 先定义存储配置 const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, path.join(__dirname, '../../uploads/')); }, filename: (req, file, cb) => { const extArray = file.mimetype.split("/"); const extension = extArray[extArray.length - 1]; cb(null, `${file.fieldname}-${Date.now()}.${extension}`); } }); // 在控制器中使用 @Post('upload') @UseInterceptors(FilesInterceptor('files[]', 20, { storage })) public async onUpload(@UploadedFiles() files) { // 这里的files里就包含你设置的新filename了 console.log(files.map(file => file.filename)); const mediaResponse = await this.media.saveMedias(0, files); return { status: true }; }
这种方式更符合NestJS的最佳实践,不需要额外的中间件。
方案二:修复自定义中间件并移除FilesInterceptor
如果你一定要用中间件来处理上传,需要修改中间件的逻辑,让它真正执行Multer的上传处理,同时控制器里不再使用FilesInterceptor:
修复后的中间件
@Injectable() export class FilesMiddleware implements NestMiddleware { private storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, path.join(__dirname, '../../uploads/')); }, filename: (req, file, cb) => { const extArray = file.mimetype.split("/"); const extension = extArray[extArray.length - 1]; cb(null, `${file.fieldname}-${Date.now()}.${extension}`); } }); resolve(...args: any[]): MiddlewareFunction { // 调用upload.any()返回中间件函数,并直接用它处理req、res、next const upload = multer({ storage: this.storage }).any(); return upload; } }
修改后的控制器
@Post('upload') public async onUpload(@Request() req) { // 这里的req.files就是经过Multer处理后的文件对象,包含新filename console.log(req.files.map(file => file.filename)); const mediaResponse = await this.media.saveMedias(0, req.files); return { status: true }; }
别忘了在模块里注册这个中间件:
@Module({ // ...其他配置 }) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer .apply(FilesMiddleware) .forRoutes({ path: 'upload', method: RequestMethod.POST }); } }
这样修改后,你就能正确获取到自定义的文件名了。
内容的提问来源于stack exchange,提问作者Ben Beri
相关产品推荐
相关产品推荐

