【问题标题】:Filter files on the basis of extension using Multer in Express JS在 Express JS 中使用 Multer 根据扩展名过滤文件
【发布时间】:2016-12-03 19:38:53
【问题描述】:

正如问题标题所解释的,我需要根据文件扩展名过滤上传的文件。所以,我浏览了官方文档并搜索了这个网站。

我的尝试

我已经尝试过遇到的解决方案。文件正在成功上传,但问题是如何过滤文件。目前我的 Router.js 文件如下所示。

Router.JS

var multer  = require('multer');
var storage = multer.diskStorage({ //multers disk storage settings
    destination: function (req, file, cb) {
        cb(null, './public/uploads/')
    },
    limits:{
        files: 1,
        fileSize: 1024 * 1024
    },
    filename: function (req, file, cb) {
        var datetimestamp = Date.now();
        cb(null, file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length -1])
    },
    onFileUploadStart: function(file) {
        console.log("Inside uploads");
        if (file.mimetype == 'image/jpg' || file.mimetype == 'image/jpeg' || file.mimetype == 'image/png') {
            return true;
        }
        else
        {
            return false;
        }
    }
});
var upload = multer({ //multer settings
    storage: storage
}).single('profilepic');


router.post('/profile', function(req, res){
    upload(req,res,function(err){
        if(err)
        {
            console.log(err);
        }
        else
        {
            console.log("Image was uploaded");
        }
    });
});

我尝试在 onFileUploadStart 中回显某些内容以检查它是否进入该函数。但事实并非如此。除了onFileUploadStart,我还尝试了fileFilter,正如link 中提到的那样,但它没有帮助。任何建议如何解决这个问题?提前致谢。

【问题讨论】:

标签: node.js express multer


【解决方案1】:

一个使用multer的例子:

var storage = multer.diskStorage({ //multers disk storage settings
    destination: function (req, file, cb) {
        cb(null, './public/uploads/')
    },
    filename: function (req, file, cb) {
        var datetimestamp = Date.now();
        cb(null, file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length -1])
    }
});

var upload = multer({ //multer settings
    storage: storage,
    fileFilter: function (req, file, callback) {
        var ext = path.extname(file.originalname);
        if(ext !== '.png' && ext !== '.jpg' && ext !== '.gif' && ext !== '.jpeg') {
            return callback(new Error('Only images are allowed'))
        }
        callback(null, true)
    },
    limits:{
        fileSize: 1024 * 1024
    }
}).single('profilepic');

摘自Node.js - File upload。原作者是IcemanMikhail。归属细节可以在contributor page 上找到。该源在CC BY-SA 3.0 下获得许可,可以在Documentation archive 中找到。参考主题 ID:4080 和示例 ID:14210。

【讨论】:

  • var ext = path.extname(file.originalname);你能定义path
  • @KhaledRamadan 添加var path = require('path');
  • 嗨,我对这个包 @AJ 有点陌生。我试图在上传之前验证我的 req.body,我将在哪里通过我的验证功能;如果失败,是否会向客户端发送错误响应?
  • @O'DaneBrissett 我认为该文件应该单独验证。您可以先验证req.body 中的所有输入,然后再进行文件验证。
  • 更有效的方法是删除var ext = path.extname 行并添加RegExp 以检查例如。 const allowedExtensions = new RegExp(/.(jpg|png|jpeg)$/gi) 和测试
【解决方案2】:

这很有帮助,谢谢。在我的例子中,我需要添加一个中间件来确保 JWToken 就位并使用 XHR 构建它。如果其他人需要这方面的帮助,这对我有用。在 XHR 标头中传递令牌时可以轻松完成。

客户:

    const loadHandler = event =>{
        // loadHandler mandate
    }

    const errorHandler = event => {
        // error mandate
    }

    const abortHandler = event => {
        // abort mandate
    }

    const data = new FormData()
    data.append('file', upFile)

    var formData = new FormData();
    var xhr = new window.XMLHttpRequest();

    formData.append('files', upFile); // this is a state object set onChange
    xhr.open('post', '/uploadFile', true);
    xhr.setRequestHeader('token', thetoken); // Passing token in header

    xhr.addEventListener("load", loadHandler, false);
    xhr.addEventListener("error", errorHandler, false);
    xhr.addEventListener("abort", abortHandler, false);

    xhr.send(formData);

服务器

const express = require('express'),
      app= express.Router(),
      rf = require('./RoutFuctions');
...
app.post('/uploadFile', rf.verifyToken, function (req, res, next) {
     // upload portion above
});

RoutFunctions.js

const jwt = require('jsonwebtoken')

const tokenTest = (token, res, jwt, caller, next) => {
    jwt.verify(token, process.env.SECRET_KEY, err => {
        if(err) {
          res.sendStatus(403);
          console.log('could not verify token');
        } else {
          console.log("token verified");
          next(); // Next middleware
        }
    });
}

exports.verifyToken = function(req, res, next) {

    if(req.body.token !== undefined) { // non upload scenario
        var caller = ''
        if(req.body.caller !== undefined) caller = req.body.caller;
        tokenTest(req.body.token, res, jwt, caller, next)

    } else {  // attempt to extract token in XHR header upload scenario

      if(req.headers.token !== undefined){
          var token = req.headers.token
          tokenTest(req.headers.token, res, jwt, caller, next)
      } else {
          res.sendStatus(403);
      }
    }
}

【讨论】:

    【解决方案3】:

    多个或单个文件的完整实现。

    注意:对于单个文件,请使用 .single('filename') 或 .array('filename',1)

      const express = require("express");
      const app = express();
      var session = require('express-session')
      const multer = require("multer");
      const path = require("path");
      var storage = multer.diskStorage({ //multers disk storage settings
        destination: function (req, file, cb) {
            cb(null, path.join(__dirname,"uploads"))
        },
        filename: function (req, file, cb) {
            var datetimestamp = Date.now();
            cb(null, file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length -1])
        }
      });
    
      var upload = multer({ //multer settings
        storage: storage,
        fileFilter: function (req, file, callback) {
            var ext = path.extname(file.originalname);
            if(ext !== '.png' && ext !== '.jpg' && ext !== '.gif' && ext !== '.jpeg') {
                return callback(new Error('Only images are allowed'))
            }
            callback(null, true)
        },
        limits:{
            fileSize: 1024 * 1024
        }
      }).array('profile',2);
      app.post("/upload", upload,(req, res) => {
        res.json({
          msg:"uploaded"
        })
      });
    
      app.use((err,req,res,next)=>{
        console.log(err.message);
        res.status(404).json({
          msg:err.message
        })
      })
      app.listen(
        8080,
        (error) => {
          if (error) {
            console.log("error");
          }
        },
        () => {
          console.log("listening at port 8080");
        }
      );
    
    

    注意:您可以通过扩展 Error 来创建自己的自定义错误消息,并在 err,req,res,next 块中发送自定义消息和状态

    【讨论】:

      【解决方案4】:

      我现在正在测试这个替代方案。对我来说似乎可行,但我仍在评估( 用打字稿):

      import crypto from 'crypto';
      import multer, { FileFilterCallback } from 'multer';
      import { resolve } from 'path';
      
      const tmpFolder = resolve(__dirname, '..', '..', 'tmp');
      
      const fileSize = 50 * 1024 * 1024;
      
      export default {
        tmpFolder,
        fileFilter: (
          request: Express.Request,
          file: Express.Multer.File,
          callback: FileFilterCallback,
        ) => {
          const acceptedTypes = file.mimetype.split('/');
      
          if (acceptedTypes[0] === 'image' || acceptedTypes[0] === 'video') {
            callback(null, true);
          } else {
            callback(null, false);
            callback(new Error('Only images and videos formats allowed!'));
          }
        },
        limits: {
          fileSize,
        },
        storage: multer.diskStorage({
          destination: tmpFolder,
          filename: (request, file, callback) => {
            const fileHash = crypto.randomBytes(16).toString('hex');
            const fileName = `${fileHash}-${file.originalname}`;
      
            return callback(null, fileName);
          },
        }),
      };
      

      【讨论】:

        【解决方案5】:

        如果你习惯web开发,可以在前端验证,不传到后端,可以试试:

        var file = files[0];  
        var imageType = /image.*/;  
        
        if (!file.type.match(imageType)) {  
             // do something  
        } 
        

        【讨论】:

        • 请注意,您的脚本仍然可以在浏览器控制台的源文件中进行操作。所以永远不要只依赖前端验证
        • 你永远不应该依赖前端验证,这是 100% 正确的,但你应该 ALSO 做前端验证,并不是所有的用户都是可以更改源代码的开发人员,其中一些人只是愚蠢和客户端验证将节省一些流量
        猜你喜欢
        • 2010-10-07
        • 1970-01-01
        • 2012-01-23
        • 2015-12-15
        • 1970-01-01
        • 2020-05-21
        • 2017-06-27
        • 1970-01-01
        • 2020-06-10
        相关资源
        最近更新 更多