NestJS多图片字段上传报Unexpected field错误求助
NestJS多文件上传报错:400 Bad Request "Unexpected field"
问题描述
本人正在学习NestJS,尝试在项目中实现图片上传功能,单图片上传可正常运行,但处理image_front、image_back、profile_image三个图片字段时,出现400 Bad Request错误,错误信息为:
{"message":"Unexpected field","error":"Bad Request","statusCode":400}
项目使用MySQL数据库,以下是原控制器代码:
@Post('personal-details') @UseInterceptors( FileInterceptor('image_front', { storage: diskStorage({ destination: './uploads/user', filename: (req, file, cb) => { const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9); const extension = file.originalname.split('.').pop(); cb(null, `img-front-${uniqueSuffix}.${extension}`); }, }), }), FileInterceptor('image_back', { storage: diskStorage({ destination: './uploads/user', filename: (req, file, cb) => { const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9); const extension = file.originalname.split('.').pop(); cb(null, `img-back-${uniqueSuffix}.${extension}`); }, }), }), FileInterceptor('profile_image', { storage: diskStorage({ destination: './uploads/user', filename: (req, file, cb) => { const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9); const extension = file.originalname.split('.').pop(); cb(null, `img-profile-${uniqueSuffix}.${extension}`); }, }), }), ) async studentPersonalData( @Body('email') email: string, @Body() personalDetailsDto: personalDetailsDto, @UploadedFile() imageFront, @UploadedFile() imageBack, @UploadedFile() profileImage, ) { try { const imageFrontFilename = imageFront ? imageFront.filename : null; const imageBackFilename = imageBack ? imageBack.filename : null; const profileImageFilename = profileImage ? profileImage.filename : null; console.log('Image front filename:', imageFrontFilename); console.log('Image back filename:', imageBackFilename); console.log('Profile image filename:', profileImageFilename); console.log('Email:', email); console.log('Personal details:', personalDetailsDto); const result = await this.userService.dataPersonalDet(email, { ...personalDetailsDto, image_front: imageFrontFilename, image_back: imageBackFilename, profile_image: profileImageFilename, }); return result; } catch (error) { console.error("Error processing personal data:", error); throw new BadRequestException("Failed to process personal data"); } }
问题原因
不能同时使用多个FileInterceptor,因为每个FileInterceptor只能处理单个文件字段,多个拦截器叠加会导致解析冲突,从而触发"Unexpected field"错误。
解决方案
改用FileFieldsInterceptor来处理多个不同名称的文件字段,它专门用于处理多个命名文件的上传场景。
修正后的代码
import { FileFieldsInterceptor } from '@nestjs/platform-express'; import { UploadedFiles } from '@nestjs/common'; @Post('personal-details') @UseInterceptors( FileFieldsInterceptor([ { name: 'image_front', maxCount: 1 }, { name: 'image_back', maxCount: 1 }, { name: 'profile_image', maxCount: 1 }, ], { storage: diskStorage({ destination: './uploads/user', filename: (req, file, cb) => { const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9); const extension = file.originalname.split('.').pop(); // 根据字段名生成不同的前缀 let prefix = ''; switch(file.fieldname) { case 'image_front': prefix = 'img-front'; break; case 'image_back': prefix = 'img-back'; break; case 'profile_image': prefix = 'img-profile'; break; } cb(null, `${prefix}-${uniqueSuffix}.${extension}`); }, }), }), ) async studentPersonalData( @Body('email') email: string, @Body() personalDetailsDto: personalDetailsDto, @UploadedFiles() files: { image_front?: Express.Multer.File[], image_back?: Express.Multer.File[], profile_image?: Express.Multer.File[] }, ) { try { const imageFrontFilename = files.image_front?.[0]?.filename || null; const imageBackFilename = files.image_back?.[0]?.filename || null; const profileImageFilename = files.profile_image?.[0]?.filename || null; console.log('Image front filename:', imageFrontFilename); console.log('Image back filename:', imageBackFilename); console.log('Profile image filename:', profileImageFilename); console.log('Email:', email); console.log('Personal details:', personalDetailsDto); const result = await this.userService.dataPersonalDet(email, { ...personalDetailsDto, image_front: imageFrontFilename, image_back: imageBackFilename, profile_image: profileImageFilename, }); return result; } catch (error) { console.error("Error processing personal data:", error); throw new BadRequestException("Failed to process personal data"); } }
关键修改点
- 替换多个
FileInterceptor为单个FileFieldsInterceptor,配置需要处理的文件字段列表及每个字段的最大上传数量。 - 使用
@UploadedFiles()装饰器接收所有上传的文件,而不是多个@UploadedFile()。 - 在文件名生成逻辑中,通过
file.fieldname判断当前文件对应的字段,生成对应前缀的文件名。 - 访问文件时,需通过数组索引获取(因为
maxCount设为1,所以取[0])。
内容的提问来源于stack exchange,提问作者Aiswarya KV
相关产品推荐
相关产品推荐

