使用skipper在上传文件到MongoDB之前检查Sails.js的内容(有效文件、图像调整大小等)。

4
我正在创建一个文件上传系统。我的后端是Sails.js(10.4),它作为我的独立前端(Angular)的API。
我选择将要上传的文件存储到我的MongoDB实例中,并使用Sails的内置文件上传模块Skipper。我正在使用适配器skipper-gridfs(https://github.com/willhuang85/skipper-gridfs)将文件上传到mongo。
现在,上传文件本身不是问题:我在客户端使用dropzone.js,将上传的文件发送到/api/v1/files/upload。文件将被上传。
为了实现这一目标,在我的FileController中使用以下代码:
module.exports = {
    upload: function(req, res) {
        req.file('uploadfile').upload({
            // ...any other options here...
            adapter: require('skipper-gridfs'),
            uri: 'mongodb://localhost:27017/db_name.files'
        }, function(err, files) {
            if (err) {
                return res.serverError(err);
            }
            console.log('', files);
            return res.json({
                message: files.length + ' file(s) uploaded successfully!',
                files: files
            });
        });
    }
};

现在问题是:在上传文件之前,我想对文件进行一些操作。具体来说,有两个方面:
  1. 检查文件是否被允许:内容类型头与我想要允许的文件类型是否匹配?(jpeg、png、pdf等基本文件)。
  2. 如果文件是图像,则使用imagemagick(或类似工具)将其调整为几个预定义大小。
  3. 添加文件特定信息,这些信息也将保存到数据库中:参考上传文件的用户和文件所属的模型(即文章/评论)。
我不知道从哪里开始或如何实现这种功能。因此,任何帮助都将不胜感激!
2个回答

10

好的,经过一段时间的尝试,我终于找到了一种看起来似乎可以工作的方法。

可能还有改进的余地,但目前它可以实现我想要的功能:

upload: function(req, res) {
    var upload = req.file('file')._files[0].stream,
        headers = upload.headers,
        byteCount = upload.byteCount,
        validated = true,
        errorMessages = [],
        fileParams = {},
        settings = {
            allowedTypes: ['image/jpeg', 'image/png'],
            maxBytes: 100 * 1024 * 1024
        };

    // Check file type
    if (_.indexOf(settings.allowedTypes, headers['content-type']) === -1) {
        validated = false;
        errorMessages.push('Wrong filetype (' + headers['content-type'] + ').');
    }
    // Check file size
    if (byteCount > settings.maxBytes) {
        validated = false;
        errorMessages.push('Filesize exceeded: ' + byteCount + '/' + settings.maxBytes + '.');
    }

    // Upload the file.
    if (validated) {
        sails.log.verbose(__filename + ':' + __line + ' [File validated: starting upload.]');

        // First upload the file
        req.file('file').upload({}, function(err, files) {
            if (err) {
                return res.serverError(err);
            }

            fileParams = {
                fileName: files[0].fd.split('/').pop().split('.').shift(),
                extension: files[0].fd.split('.').pop(),
                originalName: upload.filename,
                contentType: files[0].type,
                fileSize: files[0].size,
                uploadedBy: req.userID
            };

            // Create a File model.
            File.create(fileParams, function(err, newFile) {
                if (err) {
                    return res.serverError(err);
                }
                return res.json(200, {
                    message: files.length + ' file(s) uploaded successfully!',
                    file: newFile
                });
            });
        });
    } else {
        sails.log.verbose(__filename + ':' + __line + ' [File not uploaded: ', errorMessages.join(' - ') + ']');

        return res.json(400, {
            message: 'File not uploaded: ' + errorMessages.join(' - ')
        });
    }

},

我选择使用本地文件存储而不是skipper-gridfs,但是思路是相同的。虽然它还没有像应该那样完整,但它是验证文件类型和大小等简单内容的简单方法。如果有更好的解决方案,请发布出来 :)!


1
您可以为.upload()函数指定回调函数。例如:
req.file('media').upload(function (error, files) {
  var file;

  // Make sure upload succeeded.
  if (error) {
    return res.serverError('upload_failed', error);
  }

  // files is an array of files with the properties you want, like files[0].size
}

您可以在.upload()的回调函数中,调用适配器并上传文件。

如果我理解正确的话,我应该首先使用默认的.upload函数,它将把上传的文件存储在.tmp/uploads目录中,在第一个上传函数的回调中执行自定义操作(如检查文件类型等),然后使用skipper-gridfs将其发送到Mongo?在第一个回调中仍然可以对文件调用.upload吗? - Lars Dol
我认为是的。我没有看到任何 validate() 回调函数。 - Wesley Overdijk
也许我做了一些愚蠢的事情,但是当我在回调函数中尝试以下操作时:files[0].upload({'adapter: require('skipper-gridfs'), uri: 'mongodb://localhost:27017/evolution_api_v1.files'}, function(err, files) { ... });控制台会报错“Object has no method upload”。这有点像我预料的。而且我觉得上传文件两次有点奇怪。在上传之前拦截文件可能更好一些...不确定是否可能 :). - Lars Dol

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