Node.js使用Multer上传图片时req.body为空无法获取表单字段数据
问题现象
Node.js项目使用Multer实现图片上传功能时,图片可正常完成上传,但无法从req.body获取表单内的文本输入字段数据,打印req.body得到空对象{}。经测试,移除表单的enctype="multipart/form-data"属性后req.body可正常返回数据,但此时图片无法上传。
现存代码
前端表单
<form action="/postRoute" method="POST" enctype="multipart/form-data"> <div class="form-group row"> <div class="col-sm-6 mb-3 mb-sm-0"> <input type="text" placeholder="Title" name="title"> </div> <div class="col-sm-6"> <input type="text" placeholder="Description" name="description"> </div> </div> <div class="file-field input-field"> <div class="btn grey"> <span>Image</span> <input type="file" name="image" multiple> </div> </div> <button type="submit" class="btn btn-primary btn-user btn-block"> List </button> </form>
路由处理逻辑
router.post('/postRoute', (req, res) => { console.log(req.body); upload(req, res, (err) => { if(err) { throw err; } else { console.log('logging files'); console.log(req.files); if(req.files.length <= 0) { res.render('listing', { msg: 'Error: No File Selected!' }) } else { let list = Listing(); list.title = title; list.description = description; list.photos = req.files[0].filename list.save((err) => { if(err) throw err; req.flash('success', 'Product Listed Successfully!') res.redirect('/') }) } } }) })
Multer配置
//Set Storage Engine const storage = multer.diskStorage({ destination: './public/uploads/', filename: function(req, file, cb) { cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname)); } }) //Init Upload const upload = multer({ storage: storage, llmits: {fileSize: 1000000}, fileFilter: (req, file, cb) => { checkFileType(file, cb); } }).array('image') //Check File Type function checkFileType (file, cb) { //Allowed ext const fileType = /jpeg|jpg|png|gif/; //Check ext const extname = fileType.test(path.extname(file.originalname).toLowerCase()); //Check Mime const mimetype = fileType.test(file.mimetype) if(mimetype && extname) { return cb(null, true); } else { cb('Error: Images Only!'); } }
根因分析
Express内置的express.urlencoded中间件仅能解析application/x-www-form-urlencoded格式的请求,无法处理multipart/form-data格式的请求体。Multer的解析逻辑是流式处理请求,处理完成后才会把文本字段挂载到req.body上:
- 在调用
upload()方法之前就读取/打印req.body,此时Multer还未开始解析请求流,拿到的自然是空对象 - 路由代码中直接引用了未定义的
title、description变量,没有从req.body中取值 - Multer配置中参数名拼写错误,
llmits应为limits,导致文件大小限制不生效
修复方案
- 确认项目入口文件正确配置基础解析中间件(若已配置可跳过):
// 项目入口app.js/index.js app.use(express.urlencoded({ extended: false })); app.use(express.json());
- 调整路由逻辑,所有
req.body、req.files的取值必须放在Multer解析完成后执行,不要在调用upload前读取请求体:
推荐使用Express中间件写法,逻辑更简洁:
router.post('/postRoute', upload, (req, res) => { // 解析完成后可直接读取req.body、req.files console.log(req.body); // 可正常获取title、description字段 console.log(req.files); // 可正常获取上传的文件列表 if (req.files.length <= 0) { return res.render('listing', { msg: 'Error: No File Selected!' }) } // 正确从req.body中取值,替换原来未定义的变量 const list = new Listing(); list.title = req.body.title; list.description = req.body.description; list.photos = req.files[0].filename; list.save((err) => { if (err) throw err; req.flash('success', 'Product Listed Successfully!') res.redirect('/') }) })
若保留手动调用upload的写法,必须把取值逻辑放到upload的回调内部:
router.post('/postRoute', (req, res) => { // 禁止在这里读取req.body!此时未解析 upload(req, res, (err) => { if (err) throw err; // 解析完成后再读取req.body const { title, description } = req.body; // 后续业务逻辑... }) })
- 修正Multer配置中的拼写错误:
const upload = multer({ storage: storage, // 修正llmits为limits limits: { fileSize: 1000000 }, fileFilter: (req, file, cb) => { checkFileType(file, cb); } }).array('image')
内容的提问来源于stack exchange,提问作者Umair Nadeem
相关产品推荐
相关产品推荐

