您的位置:首页 > Web前端 > Node.js

nodejs使用multer中间件上传混合表单提交(文件和非文件普通文本域)

2017-05-08 19:10 656 查看
我的一个表单包括几个input(type=’text’)普通的文本域和input(type=’file’),两者同属一个表单,form设置enctype=’multipart/form-data’。需要混合上传,savePoster是保存文件逻辑,save是保存信息(文本域提交过来的)逻辑

前端页面(jade模板)最简化后大致是这样的:

form(method='post', action='/admin/movie/save' enctype='multipart/form-data')
input(type="file", name="uploadPoster")
input(type="text", name="movie[flash]", value=movie.flash)


我们在路由里是这样处理的

router.post('/admin/movie/save',       User.signinRequired, User.permission, Movie.savePoster, Movie.save);


理想状态:

文件上传和文本域同属一个表单,并且表单设置enctype=’multipart/form-data’

在savePoster里,获取上传的文件通过第三方中间件比如multer,multiparty等,req.file(s)可以获取到文件

在save中,获取表单中其他普通文本域的movie对象(包括movie[title], movie[director],movie[year]等等)可以通过body-parser的req.body.movie获取

我的情况:

在设置enctype=’multipart/form-data’后,文件能正常接收,可以在multer中间件提供的方法中用req.file获取文件信息,打印req.file:

{ fieldname: 'uploadPoster',
originalname: 'b922270259dece707ef6c6a50259a406_r.png',
encoding: '7bit',
mimetype: 'image/png',
destination: 'public/uploads',
filename: 'uploadPoster_1494237299545.png',
path: 'public\\uploads\\uploadPoster_1494237299545.png',
size: 134815 }


但是save里,req.body.movie._id获取不到了,提示:

Cannot read property 'id' of undefined


分析:

1.我们把事情弄简单点,不设置enctype=’multipart/form-data’,默认为application/x-www-form-urlencoded 描述:在发送前编码所有字符(默认)

点击提交按钮浏览器请求是这样的(通过Formdata):



savePoster方法里获取不到的req.file,因为表单已经被编码了所有字符,uploadPoster只是一个文件名,不是一个文件数据,save方法里正常获取movie对象(包括movie[title], movie[director],movie[year]等等);

2.设置enctype=’multipart/form-data’

描述:不对字符编码,在使用包含文件上传控件的表单时,必须使用该值。

点击提交按钮浏览器请求是这样的:



这里普通文本域已经不被编码发送给后台了,后台savePoster中只能通过multer中间件提供的方法中用req.file获取文件,在save中通过req.body(我们要获取的是req.body.movie对吧,获取不到)获取不到。这里浏览器是通过Request.payload发送普通文本域表单数据,是由boundary拼接而成(这里又涉及到ff和chrome的差异了),总之我们用req.body指定是获取不到了,在java中倒是可以通过inputstream获取,这块我也不是很了解。

解决办法:

查了很多资料,终于自己想通了. multer支持在获取文件数据同时获取表单域参数(果然看官方文档加上自己理解才是最好的)

multer官方文档: multer文件上传中间件官方文档 –npmjs

var express = require('express')
var multer  = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express()app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file 是 name为`avatar` 文件的信息
// req.body 将具有文本域数据, 如果存在的话})


在movie.js中

/*savePoster*/
exports.savePoster = function(req, res, next) {
var singleFileUpload=multer.single('uploadPoster');         //设置上传方式为单文件上传
singleFileUpload(req, res, function(err){
if (err) {
return  console.log(err);
}

req.body = req.body;
//由于设置了enctype='multipart/form-data',我们在save方法里取req.body是取不到值的,这里使用multer的req.body能获取文本域的值,将multer里的req.body赋给当前的req.body,并next传给save方法
console.log(req.file);
next();
});

}


视频里面是直接在savePoster里配置multipart,我用的是multer,singleFileUpload=multer..是我引入的multer的配置文件,里面包括了multer中间件和设置好的参数(目录,文件大小限制等),所以我在这里可以直接用req.file获取接收到的文件(包括req.file.originalName等等).看代码里面的注释差不多解析清楚了。

exports.save = function(req, res) {
var movieObj = req.body.movie;
var id = movieObj._id;
...


结果:

成功在savePoster中获取req.file,在save中获取req.body.movie

后记:

我还傻逼兮兮的问能不能分开上传,不放在一个表单里上传。好可耻。哦,对了,用formidable的同学可以尝试下,它也自带解析普通文本域的能力

var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
//do something with files or req.body(if its exists)
...


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息