Sails.js проверяет материал перед загрузкой файлов в MongoDB с помощью шкипера (действительные файлы, изменение размера изображения и т. д.)

В настоящее время я создаю систему загрузки файлов в своем приложении. Мой бэкенд — Sails.js (10.4), который служит API для моего отдельного интерфейса (Angular).

Я решил хранить файлы, которые я загружаю в свой экземпляр MongoDB, и использовать сборку парусов в модуле загрузки файлов 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. Добавьте информацию о файле, которая также будет сохранена в базе данных: ссылка на пользователя, загрузившего файл, и ссылка на модель (например, статью/комментарий), частью которой является файл.

Я понятия не имею, с чего начать или как реализовать такую ​​функциональность. Так что любая помощь будет принята с благодарностью!


person Lars Dol    schedule 28.08.2014    source источник


Ответы (2)


Хорошо, повозившись с этим какое-то время, мне удалось найти способ, который, кажется, работает.

Вероятно, это могло бы быть лучше, но на данный момент он делает то, что я хочу:

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 я решил использовать локальное хранилище файлов, но идея осталась прежней. Опять же, это еще не так полно, как должно быть, но это простой способ проверить такие простые вещи, как тип и размер файла. Если у кого-то есть лучшее решение, пожалуйста, опубликуйте его :)!

person Lars Dol    schedule 02.09.2014

Вы можете указать обратный вызов для функции .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().

person Wesley Overdijk    schedule 28.08.2014
comment
Итак, если я правильно понимаю, я должен сначала использовать функцию .upload по умолчанию, которая будет хранить загруженные файлы в каталоге .tmp/uploads, а в обратном вызове первой функции загрузки я должен выполнить свои пользовательские вещи (например, проверка типа файла и т. д.), а затем отправить его в Mongo с помощью skipper-gridfs? Смогу ли я по-прежнему вызывать .upload для файлов в первом обратном вызове? - person Lars Dol; 28.08.2014
comment
Я думаю, что да. Я нигде не вижу обратного вызова validate(). - person Wesley Overdijk; 28.08.2014
comment
Может быть, я делаю что-то глупое, но когда я пытаюсь сделать следующее в обратном вызове: files[0].upload({'adapter: require('skipper-gridfs'), uri: 'mongodb://localhost:27017/evolution_api_v1 .files'}, function(err, files) { ... }); Консоль умирает, выплевывая «Объект не имеет метода загрузки». Вроде как я и ожидал. Также я чувствую, что это немного странно, что необходимо загрузить файл дважды. Было бы лучше перехватить файл до того, как он будет каким-то образом загружен. Хотя не уверен, что это возможно :). - person Lars Dol; 28.08.2014