使用 multer 上传多个文件,但来自不同的字段?
Posted
技术标签:
【中文标题】使用 multer 上传多个文件,但来自不同的字段?【英文标题】:Uploading multiple files with multer, but from different fields? 【发布时间】:2016-07-05 22:35:13 【问题描述】:如何让 multer 接受来自多个文件类型字段的文件?
我有以下代码上传单个文件,在 node.js 中使用 multer:
var storage = multer.diskStorage(
destination: function (req, file, callback)
callback(null, './public/uploads');
,
filename: function (req, file, callback)
callback(null, file.fieldname + '-' + Date.now());
);
var upload = multer( storage : storage );
app.post('/rest/upload', upload.array('video', 1), function(req, res, next)
...
从下面的表格中,在只有视频字段有值的情况下(如果我同时指定两者,我会收到“意外字段”错误):
<form action="/rest/upload" method="post" enctype="multipart/form-data">
<label>Video file: </label> <input type="file" name="video"/>
<label>Subtitles file: </label> <input type="file" name="subtitles"/>
<input type="submit"/>
</form>
从文档中不清楚如何解决这个问题?任何建议,将不胜感激。顺便说一句,我尝试了以下参数变化,但没有成功:
app.post('/rest/upload', [upload.array('video', 1), upload.array('subtitles', 1)] ...
app.post('/rest/upload', upload.array('video', 1), upload.array('subtitles', 1), ...
app.post('/rest/upload', upload.array(['video', 'subtitles'], 1), ...
【问题讨论】:
【参考方案1】:您是否尝试使用multer().any()?
【讨论】:
我没有,尽管我会使用 uploads.fields() 方法,因为文档表明 any() 从处理和安全的角度来看可能不是最好的方法。【参考方案2】:你要的是upload.fields()
:
app.post('/rest/upload',
upload.fields([
name: 'video', maxCount: 1
,
name: 'subtitles', maxCount: 1
]), function(req, res, next)
// ...
【讨论】:
缺少扩展名,请更改。谢谢 @RishavKumar 你能详细说明一下吗?您是指文件扩展名还是说 API 已更改或?【参考方案3】:使用 Multer 从不同页面上不同表单的两个字段上传文件 在此示例中,我有两个字段 - 简历和图像。以一种形式恢复,以另一种形式恢复图像。两者都在不同的页面上。 首先导入依赖
const path = require('path'); // for getting file extension
const multer = require('multer'); // for uploading files
const uuidv4 = require('uuidv4'); // for naming files with random characters
定义fileStorage和fileFilter:
const fileStorage = multer.diskStorage(
destination: (req, file, cb) => // setting destination of uploading files
if (file.fieldname === "resume") // if uploading resume
cb(null, 'resumes');
else // else uploading image
cb(null, 'images');
,
filename: (req, file, cb) => // naming file
cb(null, file.fieldname+"-"+uuidv4()+path.extname(file.originalname));
);
const fileFilter = (req, file, cb) =>
if (file.fieldname === "resume") // if uploading resume
if (
file.mimetype === 'application/pdf' ||
file.mimetype === 'application/msword' ||
file.mimetype === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
) // check file type to be pdf, doc, or docx
cb(null, true);
else
cb(null, false); // else fails
else // else uploading image
if (
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'
) // check file type to be png, jpeg, or jpg
cb(null, true);
else
cb(null, false); // else fails
;
multer的中间件
app.use(
multer(
storage: fileStorage,
limits:
fileSize:'2mb'
,
fileFilter: fileFilter
).fields(
[
name: 'resume',
maxCount: 1
,
name: 'image',
maxCount: 1
]
)
);
然后调用你的路线。为了安全起见,您可能需要同时添加 csrf 保护或身份验证。但这应该可以正常工作。
【讨论】:
非常感谢您的澄清,它帮助我更好地理解。如果出现错误(disallow if statements as the only statement in else blocks (no-lonely-if)),您可以通过使用三元运算符来修复它,以及我使用的控制器上的问题resume: req.files.resume, image: req.files.image
【参考方案4】:
如果您想从同一个表单上传多个文件/图像,我使用了下面的代码,它工作正常。图像的路径存储在数据库中;我将跳过数据库路径,直接进入上传功能以及字段如何传递给保存功能。
const path = require('path');
const multer = require('multer');
const storage = multer.diskStorage(
destination: (req, file, cb) =>
if (file.fieldname === "profile")
cb(null, './uploads/profiles/')
else if (file.fieldname === "natid")
cb(null, './uploads/ids/');
else if (file.fieldname === "certificate")
cb(null, './uploads/certificates/')
,
filename:(req,file,cb)=>
if (file.fieldname === "profile")
cb(null, file.fieldname+Date.now()+path.extname(file.originalname));
else if (file.fieldname === "natid")
cb(null, file.fieldname+Date.now()+path.extname(file.originalname));
else if (file.fieldname === "certificate")
cb(null, file.fieldname+Date.now()+path.extname(file.originalname));
);
const upload = multer(
storage: storage,
limits:
fileSize: 1024 * 1024 * 10
,
fileFilter: (req, file, cb) =>
checkFileType(file, cb);
).fields(
[
name:'profile',
maxCount:1
,
name: 'natid', maxCount:1
,
name: 'certificate', maxCount:1
]
);
function checkFileType(file, cb)
if (file.fieldname === "certificate")
if (
file.mimetype === 'application/pdf' ||
file.mimetype === 'application/msword' ||
file.mimetype === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
) // check file type to be pdf, doc, or docx
cb(null, true);
else
cb(null, false); // else fails
else if (file.fieldname === "natid" || file.fieldname === "profile")
if (
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'||
fiel.mimetype==='image/gif'
) // check file type to be png, jpeg, or jpg
cb(null, true);
else
cb(null, false); // else fails
//at the save function
upload(req, res, (err) =>
if (err)
console.log(err);
else
if (req.file == "undefined")
console.log("No image selected!")
else
let datecreated = new Date();
let fullnames = req.body.firstname + ' ' + req.body.lastname;
let formatedphone = '';
let phone = req.body.personalphone;
if (phone.charAt(0) == '0')
formatedphone = '+254' + phone.substring(1);
else if ((phone.charAt(0) == '+') && (phone.length > 12 || phone.length <= 15))
formatedphone = phone
let teachers =
"teacherid": teacherid,
"schoolcode": req.body.schoolcode,
"fullnames": fullnames,
"email": req.body.email,
"dateofbirth": req.body.dateofbirth,
"nationalid": req.body.nationalid,
"personalphone": formatedphone,
"profile": req.files.profile[0].path,
"natid": req.files.natid[0].path,
"certificate":req.files.certificate[0].path
connection.query('INSERT INTO teachers SET ?', teachers, (error, results, fields) => `enter code here`
if (error)
res.json(
status: false,
message: 'there are some error with query'
)
console.log(error);
else console.log("Saved successfully");
【讨论】:
你能解释一下这个代码块末尾发生了什么吗?至少,缩进似乎是关闭的。但是,似乎还有一个与该功能无关的配置块。我想这就是您对将其放在save()
函数中的评论吗?如果是这样,我建议将其分解为单独的代码块。
这里是完整的保存功能:下面
谢谢!您可以(并且在这种情况下应该)编辑您的答案,以将 Save()
函数作为同一答案的一部分。这样,它们就不会随着时间的流逝而分离。你能做到吗?
您的答案应该包括解释,正如 mhmdk 在他们的回答中所做的那样。以目前的形式,它有被否决的风险。【参考方案5】:
upload(req, res, (err) =>
if (err)
console.log(err);
else
if (req.file == "undefined")
console.log("No image selected!")
else
let datecreated = new Date();
let fullnames = req.body.firstname + ' ' + req.body.lastname;
let formatedphone = '';
let phone = req.body.personalphone;
if (phone.charAt(0) == '0')
formatedphone = '+254' + phone.substring(1);
else if ((phone.charAt(0) == '+') && (phone.length > 12 || phone.length <= 15))
formatedphone = phone
let teachers =
"teacherid": teacherid,
"schoolcode": req.body.schoolcode,
"fullnames": fullnames,
"email": req.body.email,
"dateofbirth": req.body.dateofbirth,
"nationalid": req.body.nationalid,
"personalphone": formatedphone,
"profile": req.files.profile[0].path,
"natid": req.files.natid[0].path,
"certificate":req.files.certificate[0].path
connection.query('INSERT INTO teachers SET ?', teachers, (error, results, fields) =>
if (error)
res.json(
status: false,
message: 'there are some error with query'
)
console.log(error);
else
console.log('保存成功');
【讨论】:
【参考方案6】:这对我有用。完整的例子
var multer = require('multer')
var storage = multer.diskStorage(
destination: function(req, file, callback)
callback(null, './public/audio');
,
filename: function(req, file, callback)
console.log(file);
if(file.originalname.length>6)
callback(null, file.fieldname + '-' + Date.now() + file.originalname.substr(file.originalname.length-6,file.originalname.length));
else
callback(null, file.fieldname + '-' + Date.now() + file.originalname);
);
const upload = multer( storage: storage );
router.post('/save/audio',upload.fields([
name: 'audio', maxCount: 1
,
name: 'graphic', maxCount: 1
]) ,(req, res) =>
const audioFile = req.files.audio[0];
const audioGraphic = req.files.graphic[0];
const fileName = req.body.title;
saveAudio(fileName,audioFile.filename,audioGraphic.filename,req.body.artist,function (error,success)
req.flash('success','File Uploaded Successfully')
res.redirect('/')
);
)
【讨论】:
以上是关于使用 multer 上传多个文件,但来自不同的字段?的主要内容,如果未能解决你的问题,请参考以下文章