【问题标题】:Uploading multiple files with multer, but from different fields?使用 multer 上传多个文件,但来自不同的字段?
【发布时间】:2021-04-26 15:34:19
【问题描述】:

如何让 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),  ...

【问题讨论】:

    标签: node.js multer


    【解决方案1】:

    如果您想从同一个表单上传多个文件/图像,我使用了下面的代码,它工作正常。图像的路径存储在数据库中;我将跳过数据库路径,直接进入上传功能以及字段如何传递给保存功能。

        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 在他们的回答中所做的那样。以目前的形式,它有被否决的风险。
    【解决方案2】:

    这对我有用。完整的例子

    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('/')
      });
    
    })
    

    【讨论】:

      【解决方案3】:
      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('保存成功');}

      【讨论】:

        【解决方案4】:

        使用 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 保护或身份验证。但这应该可以正常工作。

        【讨论】:

        【解决方案5】:

        你要的是upload.fields():

        app.post('/rest/upload',
                 upload.fields([{
                   name: 'video', maxCount: 1
                 }, {
                   name: 'subtitles', maxCount: 1
                 }]), function(req, res, next){
          // ...
        }
        

        【讨论】:

        • 缺少扩展名,请更改。谢谢
        • @RishavKumar 你能详细说明一下吗?您是指文件扩展名还是说 API 已更改或?
        【解决方案6】:

        您是否尝试使用multer().any()

        【讨论】:

        • 我没有,尽管我会使用 uploads.fields() 方法,因为文档表明 any() 从处理和安全的角度来看可能不是最好的方法。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-11-13
        • 1970-01-01
        • 2021-03-24
        • 2017-01-13
        • 2018-09-04
        • 1970-01-01
        相关资源
        最近更新 更多