使用 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 上传多个文件,但来自不同的字段?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Multer 上传文件,而不知道它们的字段名

Multer-s3 在手机上上传空文件

使用 Multer 将 csv 文件上传到 Node.js 时出现意外字段

将所有multer上传的文件移动到Nodejs中的新目的地

上传文件时 Multer 出现意外的字段错误

如何使用 bootstrap-vue 上传多个文件