Загрузка потока Node.js напрямую в Google Cloud Storage

У меня есть приложение Node.js, работающее на экземпляре виртуальной машины Google Compute, которое получает загрузку файлов непосредственно из запросов POST (не через браузер) и передает входящие данные в Google Cloud Storage (GCS).

Я использую Restify, потому что мне не нужны дополнительные функции Express, потому что он позволяет легко передавать входящие данные.

Я создаю случайное имя файла для файла, принимаю входящее req и отправьте его аккуратной маленькой обёртке Node для GCS (находится здесь: https://github.com/bsphere/node-gcs), которая отправляет запрос PUT в GCS. Документацию по GCS с использованием PUT можно найти здесь: https://developers.google.com/storage/docs/reference-methods... там написано Content-Length не требуется при использовании chunked transfer encoding,

Хорошая новость: файл создается внутри соответствующего хранилища GCS!

Плохие новости:

  1. Я не понял, как получить расширение входящего файла из Restify (обратите внимание, я вручную устанавливаю ".jpg" и content-type вручную).

  2. В файле наблюдается небольшое повреждение (почти наверняка что-то не так с запросом PUT). Если я загружаю POST-файл из Google, OSX сообщает мне, что он поврежден... НО, если я использую PhotoShop, он открывается и выглядит просто отлично.

Обновление / Решение

Как указано vkurchatkin Мне нужно было разобрать request объект вместо того, чтобы просто передать все это в GCS. Попробовав зажигалку busboy модуль, я решил, что это было намного проще в использовании multiparty, Для динамической настройки Content-Type Я просто использовал Mimer ( https://github.com/heldr/mimer), ссылаясь на расширение файла входящего файла. Важно отметить, что, так как мы part объект, part.headers должны быть очищены. В противном случае непреднамеренная информация, в частности content-type, будут переданы и могут / будут конфликтовать с content-type мы пытаемся установить явно.

Вот соответствующий модифицированный код:

var restify = require('restify'),
    server = restify.createServer(),
    GAPI = require('node-gcs').gapitoken,
    GCS = require('node-gcs'),
    multiparty = require('multiparty'),
    Mimer = require('mimer');

server.post('/upload', function(req, res) {

    var form = new multiparty.Form();

    form.on('part', function(part){
        var fileType = '.' + part.filename.split('.').pop().toLowerCase();
        var fileName = Math.random().toString(36).slice(2) + fileType;

        // clear out the part's headers to prevent conflicting data being passed to GCS
        part.headers = null;

        var gapi = new GAPI({
            iss: '-- your -- @developer.gserviceaccount.com',
            scope: 'https://www.googleapis.com/auth/devstorage.full_control',
            keyFile: './key.pem'
        }, 
        function(err) {
            if (err) { console.log('google cloud authorization error: ' + err); }

            var headers = {
                'Content-Type': Mimer(fileType),
                'Transfer-Encoding': 'Chunked',
                'x-goog-acl': 'public-read'
            };

            var gcs = new GCS(gapi);

            gcs.putStream(part, myBucket, '/' + fileName, headers, function(gerr, gres){
                console.log('file should be there!');
            });
        });
    });
};

1 ответ

Решение

Вы не можете использовать сырье req поток, так как он выдает все тело запроса, которое является составным. Вам нужно проанализировать запрос с помощью чего-то вроде многопартийности, чтобы получить читаемый поток и все необходимые метаданные.

Другие вопросы по тегам