Node.js使用Multer同时上传图片视频时Postman报Unexpected field错误
问题原因和修复方案
错误根因
- multer的diskStorage配置参数不存在
filename1、filename2属性,官方标准属性名为filename,自定义的属性名不会被multer识别,导致文件名生成逻辑失效 - 不能在同一个路由上同时挂载两个multer单文件上传中间件:第一个multer中间件会消费完请求的formData数据流,第二个中间件无法再读取到对应字段的文件,自然抛出
Unexpected field错误 - multer的
single()方法只会将单个文件挂载到req.file上,同时上传两个不同字段的文件时需要用fields()方法,文件会挂载到复数形式的req.files上,原有控制器里读取req.file.filename1、req.file.filename2的写法不成立 - 视频MIME类型配置里多写了一个斜杠,
video//webm要改成video/webm
具体修复步骤
步骤1:合并multer配置,创建新的多文件上传中间件
新建middlewares/multer-upload.js,代码如下:
const multer = require('multer'); // 合并所有支持的MIME类型 const MIME_TYPES = { // 图片类型 'image/jpg': 'jpg', 'image/jpeg': 'jpg', 'image/png': 'png', // 视频类型 'video/mp4': 'mp4', 'video/mpeg': 'mpeg', 'video/ogg': 'ogv', 'video/mp2t': 'ts', 'video/webm': 'webm' } const storage = multer.diskStorage({ // 根据文件类型判断存储路径 destination: (req, file, callback) => { let uploadPath = 'public/images/exercise'; if (file.mimetype.startsWith('video/')) { uploadPath = 'public/videos/exercise'; } callback(null, uploadPath); }, // 统一使用官方标准的filename属性生成文件名 filename: (req, file, callback) => { let name = Math.floor(Math.random() * Math.floor(123456789)).toString(); name += Math.floor(Math.random() * Math.floor(123456789)).toString(); name += Math.floor(Math.random() * Math.floor(123456789)).toString(); name += Math.floor(Math.random() * Math.floor(123456789)).toString(); name += Date.now() + "."; const extension = MIME_TYPES[file.mimetype]; name += extension; callback(null, name) } }) // 配置同时接收image和video两个字段的单文件,对应Postman里的字段名 module.exports = multer({ storage }).fields([ { name: 'image', maxCount: 1 }, { name: 'video', maxCount: 1 } ]);
步骤2:修改路由配置
删除原来引入的两个独立multer中间件,替换为新的多文件上传中间件:
var express = require('express'); var router = express.Router(); var exerciseController = require('../controllers/exerciseController'); // 引入合并后的多文件上传中间件 const multerUpload = require('../middlewares/multer-upload'); /* GET home page. */ router.get('/show', exerciseController.show); // 只挂载一个multer中间件即可 router.post('/create', multerUpload, exerciseController.create); // 如果update接口也要同时传视频,也可以替换为multerUpload,根据自己的业务调整 router.put('/update/:id', multerUpload, exerciseController.update); module.exports = router;
步骤3:修改控制器里的文件读取逻辑
multer的fields()方法会将文件挂载到req.files对象上,每个字段对应的值是文件数组,取第一个元素的filename即可:
create:(req,res)=>{ console.log("Test1"); console.log("Test1bis"); console.log("Test2") var exerciseB = new Exercise({ ...req.body, // 从req.files中读取对应字段的文件名 image: `${req.protocol}://${req.get('host')}/images/exercise/${req.files.image[0].filename}`, video: `${req.protocol}://${req.get('host')}/videos/exercise/${req.files.video[0].filename}` }) console.log("Test3") exerciseB.save((err,exercise)=>{ if(err){ console.log("C'est le 2eme err"); return res.status(500).json({ status:500, message:err.message }) } console.log("Ca arrive jusqu'au 200"); return res.status(201).json({ status:200, message:"Exercise Created Successfully !" }) }) }
内容的提问来源于stack exchange,提问作者user17205196
相关产品推荐
相关产品推荐

