使用NodeJS Multer转换上传

3
我正在为我的用户实现一个文件/图片上传服务。在将这些图片上传到我的S3存储桶之前,我想对它们进行转换(调整大小/优化)。
目前的做法是:在前端使用多部分表单(我认为实际实现并不重要...),并在后端使用multer和multer-s3包。
以下是我实现的关键部分。
// SETUP
var multer = require('multer');
var s3 = require('multer-s3');
var storage = s3({
    dirname: 'user/uploads',
    bucket: auth.aws.s3.bucket,
    secretAccessKey: auth.aws.s3.secretAccessKey,
    accessKeyId: auth.aws.s3.accessKeyId,
    region: auth.aws.s3.region,
    filename: function (req, file, cb) {
        cb(null, Date.now());
    }
});
var upload = multer({storage: storage}).single('img');

// ROUTE
module.exports = Router()
    .post('/', function (req, res, next) {
        upload(req, res, function (err) {
            if (err) {
                return res.status(401).json({err: '...'});
            }
            return res.json({err:null,url: '..'});
        });
    });

我想要做的事情是: 在上传图像之前对其进行转换。 我不确定是否需要在这里使用multer/busboy,还是可以只使用NodeJS完成(因此我也标记了NodeJS和express)。

那么我的问题是:在上传到我的S3存储桶之前,在哪里可以拦截并转换上传的图像?


你可以在上传到S3之前将文件保存在某个临时文件夹中。如果你不想保存这些文件,那么你可以在内存中执行此操作,这取决于图像的大小,对于较大的文件,这种方法可能不适用。 - Risto Novik
另一种方法是使用AWS Lambdas,在文件被写入S3后触发特定的图像转换链。此外,这是一个相当可扩展的解决方案。图像转换通常不适合Node.js单线程模型。 - Risto Novik
除了其他列出的方法之外,还有云图像服务可以实时完成所有转换,例如Cloudinary。 - Risto Novik
感谢列出的所有方法。我知道这些服务,但它们涉及额外的费用,而我必须避免这些费用。 - boop
@Brettetete 我认为你也可以按照上面建议的使用Cloudinary的方式,因为它可以为您提供一些图像转换和处理功能。请查看此链接:http://cloudinary.com/documentation/node_image_manipulation - Solomon Ayoola
显示剩余8条评论
2个回答

9

不确定你是否仍在寻找答案,但我曾遇到同样的问题。我决定扩展multer-s3包。

我已经向原始存储库提交了一个拉取请求,但现在,您可以使用我的分支

以下是如何使用扩展版本的示例:

  var upload = multer({
    storage: multerS3({
      s3: s3,
      bucket: 'some-bucket',
      shouldTransform: function (req, file, cb) {
        cb(null, /^image/i.test(file.mimetype))
      },
      transforms: [{
        id: 'original',
        key: function (req, file, cb) {
          cb(null, 'image-original.jpg')
        },
        transform: function (req, file, cb) {
          cb(null, sharp().jpg())
        }
      }, {
        id: 'thumbnail',
        key: function (req, file, cb) {
          cb(null, 'image-thumbnail.jpg')
        },
        transform: function (req, file, cb) {
          cb(null, sharp().resize(100, 100).jpg())
        }
      }]
    })
  })

编辑:我的分支现在也可以通过npm以multer-s3-transform的名称使用。


我正在使用这段代码,但是出现了错误 Cannot find name'sharp'。我需要安装sharp的npm包还是它是内置的? - Usama Tahir
你必须实现转换... 在这个例子中,我使用了sharp,但你可以使用任何你想要的东西。 - Gregor Menih
1
你能提供一个完整的可用示例吗?我已经安装了sharp包,但是它给我报错 sharp(...).jpg不是一个函数 - Usama Tahir
我也遇到了sharp(...) .jpg不是函数的问题。我解决这个问题的方法是假设sharp不再有jpg函数。我改用.png()函数,实际上我更喜欢png格式。如果您仍希望保留jpg格式,我建议您通过https://www.npmjs.com/package/sharp查看最新的sharp信息。 - Daniel Brown
对我来说它不起作用,没有错误发生,但文件没有上传并且没有进入此函数。 var upload = multer({........}).single("file"); upload(req, res, function (err, filePath) { console.log(err, "Error"); console.log(filePath, "*************"); }); - jones
哇,你已经制作了一个完整的npm包来处理这个问题。非常感谢!这不仅应该被接受,而且应该得到一百万个赞! - Mattia Rasulo

0

我尝试使用@ItsGreg的分支,但无法使其正常工作。我通过使用{{link1:multer-s3}}标准配置并在我的文件上传端点内实现了此行为。

app.post('/files/upload',upload.single('file'),(req,res)=> {...})

我正在使用{{link2:request}}检索文件,并将缓冲区传递给{{link3:sharp}}。以下内容有效(假设您正在使用〜/ .aws /凭据):

    let request = require('request').defaults({ encoding: null });
    let dataURI = `https://s3.amazonaws.com/${process.env.AWS_S3_BUCKET}/${image.defaultUrl}`;
    request.get(dataURI, function (error, response, body) {
        if (! error && response.statusCode === 200) {
            let buffer = new Buffer(body);
            const sizes = ['thumbnail', 'medium', 'large'];
            sizes.forEach(size => {
                sharp(buffer)
                    .resize(image.sizes[size])
                    .toBuffer()
                    .then(data => {

                        // Upload the resized image Buffer to AWS S3.
                        let params = {
                            Body: data,
                            Bucket: process.env.AWS_S3_BUCKET,
                            Key: `${image.filePath}${image.names[size]}`,
                            ServerSideEncryption: "AES256",
                        };

                        s3.putObject(params, (err, data) => {
                            if (err) console.log(err, err.stack); // an error occurred
                            else console.log(data);           // successful response
                        });
                    })
            })
        }
    });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接