Загрузка потока 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!
Плохие новости:
Я не понял, как получить расширение входящего файла из Restify (обратите внимание, я вручную устанавливаю ".jpg" и
content-type
вручную).В файле наблюдается небольшое повреждение (почти наверняка что-то не так с запросом 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
поток, так как он выдает все тело запроса, которое является составным. Вам нужно проанализировать запрос с помощью чего-то вроде многопартийности, чтобы получить читаемый поток и все необходимые метаданные.