Javascript 在Express中发送上传的图像

Javascript 在Express中发送上传的图像,javascript,node.js,express,multer,Javascript,Node.js,Express,Multer,有一个使用Multer上传图像的Express应用程序。我希望能够做到的是服务于这一形象。但问题是,当上传文件时,它不会保存文件扩展名,而文件扩展名是根据我所阅读的内容出于安全目的而设计的。我需要能够做的是向相应的mime类型添加正确的扩展 技术 快车:4.15.0 穆特:1.3.0 mmmagic:0.4.5 文件结构 root server.js /uploads /images ad58c400e67362118ac1b11f6c4b6c44 .

有一个使用Multer上传图像的Express应用程序。我希望能够做到的是服务于这一形象。但问题是,当上传文件时,它不会保存文件扩展名,而文件扩展名是根据我所阅读的内容出于安全目的而设计的。我需要能够做的是向相应的mime类型添加正确的扩展

技术

  • 快车:4.15.0
  • 穆特:1.3.0
  • mmmagic:0.4.5
文件结构

root
  server.js
  /uploads
    /images
      ad58c400e67362118ac1b11f6c4b6c44
      ...
  /routes
    drinks.routes.js
    uploads.routes.js
通过邮递员把这些都查了一遍。具有表单元素
名称
标语
图像
。如果我上传“IMG_111.jpg”,该图像将通过Multer上传,验证它是图像类型,并用新名称放置在
/images/uploads
中,Multer创建唯一性的默认行为。问题是我有
文件名
,但它没有用扩展名保存

饮料.路线.js

var upload = multer({
  dest: 'uploads/images',
  fileFilter: function (req, file, callback) {
    console.log('running upload file filter');
      var fileType = file.mimetype;
      if(fileType !== 'image/png' && fileType !== 'image/jpeg' && fileType !== 'image/gif' && fileType !== 'image/jpg') {
          return callback(new Error('Only images are allowed'))
      }
      callback(null, true)
  },
}).single('image');

router.route('/').post(passport.authenticate('jwt', { session: false }), upload, function(req, res, next){
var drink = req.body;
var drinkImage = req.file;
console.log('DRINK IMAGE', drinkImage);

Drink.createDrink(drink, drinkImage, function(err, drink, drinkImage){
  console.log('creating drink');
  if(err){
    res.send(err);
  }
    res.json(drink)
  });
});
var express = require('express');
var router = express.Router();
var path = require('path');

var mmm = require('mmmagic');
var Magic = mmm.Magic;
var magic = new Magic(mmm.MAGIC_MIME_TYPE);

router.use(function(req, res, next){
  next();
});

router.route('/images/:filename')
  .get(function(req,res){
    var fileName = req.params.filename;
    var constructFile = function(res){
      magic.detectFile(__dirname + '/../uploads/images/' + fileName, function(err, result) {
        if (err) throw err;
        console.log(result);
        if (result == 'image/jpeg'){
      // return res.sendFile(__dirname + '/../uploads/images/' + fileName + '.jpg');
      res.send(express.static(path.join(__dirname, '/../uploads/images'), {index: false, extensions:['jpg']}));
    }
  });
}

constructFile(res);
  })


module.exports = router;
router.route('/images/:filename')
  .get(function(req,res){
    var fileName = req.params.filename;
    function getFileType(file, done){
      console.log('GETTING FILE TYPE');
      magic.detectFile(__dirname + '/../uploads/images/' + fileName, function(err, result) {
        if (err) return done(err);

        res.setHeader('Content-Type', result)
        fs.createReadStream(path.join(__dirname + '/../uploads/images/', req.params.filename)).pipe(res)
    });
  }
  getFileType();
})
因此,我可以上传文件,验证文件,保存一个唯一的名称,没有扩展名的文件。我遇到的困难是检查所请求图像的mime类型,附加一个扩展名并在响应中发送回去

我最初的想法是使用请求的图像名称创建一个路由,使用mmmagic检测mime类型,添加扩展名并提供该文件。但是,所有这方面的尝试都失败了

上传.routes.js

var upload = multer({
  dest: 'uploads/images',
  fileFilter: function (req, file, callback) {
    console.log('running upload file filter');
      var fileType = file.mimetype;
      if(fileType !== 'image/png' && fileType !== 'image/jpeg' && fileType !== 'image/gif' && fileType !== 'image/jpg') {
          return callback(new Error('Only images are allowed'))
      }
      callback(null, true)
  },
}).single('image');

router.route('/').post(passport.authenticate('jwt', { session: false }), upload, function(req, res, next){
var drink = req.body;
var drinkImage = req.file;
console.log('DRINK IMAGE', drinkImage);

Drink.createDrink(drink, drinkImage, function(err, drink, drinkImage){
  console.log('creating drink');
  if(err){
    res.send(err);
  }
    res.json(drink)
  });
});
var express = require('express');
var router = express.Router();
var path = require('path');

var mmm = require('mmmagic');
var Magic = mmm.Magic;
var magic = new Magic(mmm.MAGIC_MIME_TYPE);

router.use(function(req, res, next){
  next();
});

router.route('/images/:filename')
  .get(function(req,res){
    var fileName = req.params.filename;
    var constructFile = function(res){
      magic.detectFile(__dirname + '/../uploads/images/' + fileName, function(err, result) {
        if (err) throw err;
        console.log(result);
        if (result == 'image/jpeg'){
      // return res.sendFile(__dirname + '/../uploads/images/' + fileName + '.jpg');
      res.send(express.static(path.join(__dirname, '/../uploads/images'), {index: false, extensions:['jpg']}));
    }
  });
}

constructFile(res);
  })


module.exports = router;
router.route('/images/:filename')
  .get(function(req,res){
    var fileName = req.params.filename;
    function getFileType(file, done){
      console.log('GETTING FILE TYPE');
      magic.detectFile(__dirname + '/../uploads/images/' + fileName, function(err, result) {
        if (err) return done(err);

        res.setHeader('Content-Type', result)
        fs.createReadStream(path.join(__dirname + '/../uploads/images/', req.params.filename)).pipe(res)
    });
  }
  getFileType();
})

尝试遵循这一点,这使我找到了
express.static
。但我现在还不知道我是否走在正确的轨道上,只是错过了一些东西,或者我是否应该从不同的角度来看待这个问题

您必须首先配置multer上载程序。试试这个:

var multer = require('multer');
//This is for preventing multer from giving name without extention
var storage = multer.diskStorage({
  destination: function(req, file, cb) {
    cb(null, 'public/files/')
},
filename: function(req, file, cb) {
    cb(null, file.originalname);
}
});
但是,如果您希望仍然具有唯一的名称,请尝试以下操作:

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'public/files/')
  },
  filename: function (req, file, cb) {
    crypto.pseudoRandomBytes(16, function (err, raw) {
      cb(null, raw.toString('hex') + Date.now() + '.' + 
         mime.extension(file.mimetype));
    });
  }
});
var upload = multer({ storage: storage });

您必须首先配置multer上载程序。试试这个:

var multer = require('multer');
//This is for preventing multer from giving name without extention
var storage = multer.diskStorage({
  destination: function(req, file, cb) {
    cb(null, 'public/files/')
},
filename: function(req, file, cb) {
    cb(null, file.originalname);
}
});
但是,如果您希望仍然具有唯一的名称,请尝试以下操作:

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'public/files/')
  },
  filename: function (req, file, cb) {
    crypto.pseudoRandomBytes(16, function (err, raw) {
      cb(null, raw.toString('hex') + Date.now() + '.' + 
         mime.extension(file.mimetype));
    });
  }
});
var upload = multer({ storage: storage });

这不是最干净的实现,但确实有效。在这个问题上不提建议

上传.routes.js

var upload = multer({
  dest: 'uploads/images',
  fileFilter: function (req, file, callback) {
    console.log('running upload file filter');
      var fileType = file.mimetype;
      if(fileType !== 'image/png' && fileType !== 'image/jpeg' && fileType !== 'image/gif' && fileType !== 'image/jpg') {
          return callback(new Error('Only images are allowed'))
      }
      callback(null, true)
  },
}).single('image');

router.route('/').post(passport.authenticate('jwt', { session: false }), upload, function(req, res, next){
var drink = req.body;
var drinkImage = req.file;
console.log('DRINK IMAGE', drinkImage);

Drink.createDrink(drink, drinkImage, function(err, drink, drinkImage){
  console.log('creating drink');
  if(err){
    res.send(err);
  }
    res.json(drink)
  });
});
var express = require('express');
var router = express.Router();
var path = require('path');

var mmm = require('mmmagic');
var Magic = mmm.Magic;
var magic = new Magic(mmm.MAGIC_MIME_TYPE);

router.use(function(req, res, next){
  next();
});

router.route('/images/:filename')
  .get(function(req,res){
    var fileName = req.params.filename;
    var constructFile = function(res){
      magic.detectFile(__dirname + '/../uploads/images/' + fileName, function(err, result) {
        if (err) throw err;
        console.log(result);
        if (result == 'image/jpeg'){
      // return res.sendFile(__dirname + '/../uploads/images/' + fileName + '.jpg');
      res.send(express.static(path.join(__dirname, '/../uploads/images'), {index: false, extensions:['jpg']}));
    }
  });
}

constructFile(res);
  })


module.exports = router;
router.route('/images/:filename')
  .get(function(req,res){
    var fileName = req.params.filename;
    function getFileType(file, done){
      console.log('GETTING FILE TYPE');
      magic.detectFile(__dirname + '/../uploads/images/' + fileName, function(err, result) {
        if (err) return done(err);

        res.setHeader('Content-Type', result)
        fs.createReadStream(path.join(__dirname + '/../uploads/images/', req.params.filename)).pipe(res)
    });
  }
  getFileType();
})
缺少的关键部分是:

res.setHeader('Content-Type', result)
fs.createReadStream(path.join(__dirname + '/../uploads/images/', req.params.filename)).pipe(res) 

因此,现在可以上载文件,验证mime类型,存储为唯一名称,最后调用文件名,检查mime类型,将内容类型设置为mime类型并交付给客户端。

这不是最干净的实现,但确实有效。在这个问题上不提建议

上传.routes.js

var upload = multer({
  dest: 'uploads/images',
  fileFilter: function (req, file, callback) {
    console.log('running upload file filter');
      var fileType = file.mimetype;
      if(fileType !== 'image/png' && fileType !== 'image/jpeg' && fileType !== 'image/gif' && fileType !== 'image/jpg') {
          return callback(new Error('Only images are allowed'))
      }
      callback(null, true)
  },
}).single('image');

router.route('/').post(passport.authenticate('jwt', { session: false }), upload, function(req, res, next){
var drink = req.body;
var drinkImage = req.file;
console.log('DRINK IMAGE', drinkImage);

Drink.createDrink(drink, drinkImage, function(err, drink, drinkImage){
  console.log('creating drink');
  if(err){
    res.send(err);
  }
    res.json(drink)
  });
});
var express = require('express');
var router = express.Router();
var path = require('path');

var mmm = require('mmmagic');
var Magic = mmm.Magic;
var magic = new Magic(mmm.MAGIC_MIME_TYPE);

router.use(function(req, res, next){
  next();
});

router.route('/images/:filename')
  .get(function(req,res){
    var fileName = req.params.filename;
    var constructFile = function(res){
      magic.detectFile(__dirname + '/../uploads/images/' + fileName, function(err, result) {
        if (err) throw err;
        console.log(result);
        if (result == 'image/jpeg'){
      // return res.sendFile(__dirname + '/../uploads/images/' + fileName + '.jpg');
      res.send(express.static(path.join(__dirname, '/../uploads/images'), {index: false, extensions:['jpg']}));
    }
  });
}

constructFile(res);
  })


module.exports = router;
router.route('/images/:filename')
  .get(function(req,res){
    var fileName = req.params.filename;
    function getFileType(file, done){
      console.log('GETTING FILE TYPE');
      magic.detectFile(__dirname + '/../uploads/images/' + fileName, function(err, result) {
        if (err) return done(err);

        res.setHeader('Content-Type', result)
        fs.createReadStream(path.join(__dirname + '/../uploads/images/', req.params.filename)).pipe(res)
    });
  }
  getFileType();
})
缺少的关键部分是:

res.setHeader('Content-Type', result)
fs.createReadStream(path.join(__dirname + '/../uploads/images/', req.params.filename)).pipe(res) 

因此,现在可以上载文件,验证mime类型,存储为唯一名称,最后调用文件名,检查mime类型,将内容类型设置为mime类型并发送到客户端。

感谢您的响应。Multer在drinks.routes.js
var upload=Multer({…})
中配置。我想避免使用
原始名称
。要坚持使用
filename
以唯一方式存储文件,以避免重复和错误。在进一步挖掘之后,似乎应该在前端添加扩展。这使得我只需使用带有Angular的mime类型来构造图像。但是,对于a)保存扩展名(这是安全问题吗?)或B)在FETry上构造扩展名,以不同的方式配置重命名功能,使其仍然具有唯一的名称,但也具有文件扩展名,尚未找到明确的解释。我将在我的回答中添加一个例子,这似乎是一种飘忽不定的方式,昨天下午我查阅了一些例子,看到了这个实现。与试图在路由响应或前端构建内容不同,只需在上传时保存扩展,然后继续。仍在试图拼凑为什么会提到使用这种方法的安全问题。请查看此页面并查找这家伙的评论
LinusU于2015年7月22日发表的评论
。他很好地解释了一切,还提到,没有扩展名的文件仍然可以在浏览器中使用,因为浏览器并不关心这些文件,所以基本上,您可以将扩展名添加到前端的图像路径中,不会有任何问题。感谢您的回复。Multer在drinks.routes.js
var upload=Multer({…})
中配置。我想避免使用
原始名称
。要坚持使用
filename
以唯一方式存储文件,以避免重复和错误。在进一步挖掘之后,似乎应该在前端添加扩展。这使得我只需使用带有Angular的mime类型来构造图像。但是,对于a)保存扩展名(这是安全问题吗?)或B)在FETry上构造扩展名,以不同的方式配置重命名功能,使其仍然具有唯一的名称,但也具有文件扩展名,尚未找到明确的解释。我将在我的回答中添加一个例子,这似乎是一种飘忽不定的方式,昨天下午我查阅了一些例子,看到了这个实现。与试图在路由响应或前端构建内容不同,只需在上传时保存扩展,然后继续。仍在试图拼凑为什么会提到使用这种方法的安全问题。请查看此页面并查找这家伙的评论
LinusU于2015年7月22日发表的评论
。他很好地解释了一切,还提到,没有扩展名的文件在浏览器中仍然可用,因为浏览器不关心它们,所以基本上,您可以将扩展名添加到前端的图像路径中,这样就不会有问题了。