Загрузите загруженный файл в хранилище Azure blob с помощью Node
Используя Express с Node, я могу загрузить файл успешно и передать его в хранилище Azure в следующем блоке кода.
app.get('/upload', function (req, res) {
res.send(
'<form action="/upload" method="post" enctype="multipart/form-data">' +
'<input type="file" name="snapshot" />' +
'<input type="submit" value="Upload" />' +
'</form>'
);
});
app.post('/upload', function (req, res) {
var path = req.files.snapshot.path;
var bs= azure.createBlobService();
bs.createBlockBlobFromFile('c', 'test.png', path, function (error) { });
res.send("OK");
});
Это работает отлично, но Express создает временный файл и сначала сохраняет изображение, затем я загружаю его в Azure из файла. Это кажется неэффективным и ненужным шагом в этом процессе, и мне приходится управлять очисткой каталога временного файла.
Я должен иметь возможность передавать файл непосредственно в хранилище Azure с помощью метода blobService.createBlockBlobFromStream
в Azure SDK, но я недостаточно хорошо знаком с Node или Express, чтобы понять, как получить доступ к данным потока.
app.post('/upload', function (req, res) {
var stream = /// WHAT GOES HERE ?? ///
var bs= azure.createBlobService();
bs.createBlockBlobFromStream('c', 'test.png', stream, function (error) { });
res.send("OK");
});
Я нашел следующий блог, который указывает, что может быть способ сделать это, и, конечно, Express захватывает данные потока и анализирует и сохраняет его в файловой системе. http://blog.valeryjacobs.com/index.php/streaming-media-from-url-to-blob-storage/
Код vjacobs фактически загружает файл с другого сайта и передает этот поток Azure, поэтому я не уверен, что он может быть адаптирован для работы в моей ситуации.
Как я могу получить доступ и передать поток загруженных файлов непосредственно на Azure с помощью Node?
Ответы
Ответ 1
РЕШЕНИЕ (на основе обсуждения с @danielepolencic)
Используя Multiparty (npm install multiparty), fork of Formidable, мы можем получить доступ к многочастным данным, если мы отключим промежуточное ПО bodyparser() из Express (подробнее см. их заметки об этом). В отличие от Formableable, Multiparty не будет передавать файл на диск, если вы его не сообщите.
app.post('/upload', function (req, res) {
var blobService = azure.createBlobService();
var form = new multiparty.Form();
form.on('part', function(part) {
if (part.filename) {
var size = part.byteCount - part.byteOffset;
var name = part.filename;
blobService.createBlockBlobFromStream('c', name, part, size, function(error) {
if (error) {
res.send({ Grrr: error });
}
});
} else {
form.handlePart(part);
}
});
form.parse(req);
res.send('OK');
});
Подходит для @danielepolencic для того, чтобы помочь найти решение этого.
Ответ 2
Как вы можете прочитать подключить документацию промежуточного программного обеспечения, bodyparser
автоматически обрабатывает форму для вас. В вашем конкретном случае он анализирует входящие многостраничные данные и сохраняет их где-то в другом месте, а затем предоставляет сохраненный файл в хорошем формате (т.е. req.files
).
К сожалению, мы не нуждаемся (и необходимо как) черную магию прежде всего потому, что хотим иметь возможность напрямую передавать входящие данные в лазурь без попадания на диск (т.е. req.pipe(res)
). Поэтому мы можем отключить промежуточное ПО bodyparser
и самостоятельно обрабатывать входящий запрос. Под капотом bodyparser
использует node-formidable, поэтому может быть хорошей идеей повторно использовать его в нашей реализации.
var express = require('express');
var formidable = require('formidable');
var app = express();
// app.use(express.bodyParser({ uploadDir: 'temp' }));
app.get('/', function(req, res){
res.send('hello world');
});
app.get('/upload', function (req, res) {
res.send(
'<form action="/upload" method="post" enctype="multipart/form-data">' +
'<input type="file" name="snapshot" />' +
'<input type="submit" value="Upload" />' +
'</form>'
);
});
app.post('/upload', function (req, res) {
var bs = azure.createBlobService();
var form = new formidable.IncomingForm();
form.onPart = function(part){
bs.createBlockBlobFromStream('taskcontainer', 'task1', part, 11, function(error){
if(!error){
// Blob uploaded
}
});
};
form.parse(req);
res.send('OK');
});
app.listen(3000);
Основная идея заключается в том, что мы можем использовать node потоки, чтобы нам не нужно было загружать в память полный файл до мы можем отправить его на лазурь, но мы можем перенести его по мере его поступления. node -формируемый модуль поддерживает потоки, следовательно, поток потока в лазурь достигнет нашей цели.
Вы можете легко протестировать код локально, не нажимая лазурь, заменив маршрут post
на:
app.post('/upload', function (req, res) {
var form = new formidable.IncomingForm();
form.onPart = function(part){
part.pipe(res);
};
form.parse(req);
});
Здесь мы просто прокладываем запрос с входа на вывод. Вы можете узнать больше о bodyparser
здесь.
Ответ 3
Существуют различные варианты загрузки двоичных данных (например, изображений) через Azure Storage SDK для Node, а не для использования multipart.
Основываясь на определениях буфера и потока в Node и манипулируя ими, их можно обрабатывать, используя почти все методы загрузки BLOB: createWriteStreamToBlockBlob
, createBlockBlobFromStream
, createBlockBlobFromText
.
Ссылки можно найти здесь: Загрузить двоичные данные из тела запроса в хранилище BLUE в Azure в Node.js [восстановить]
Ответ 4
У людей, имеющих проблемы с .createBlockBlobFromStream, пытающимися реализовать решения, обратите внимание, что этот метод несколько изменился в более новых версиях
Старая версия:
createBlockBlobFromStream(containerName, blobName, part, size, callback)
Новая версия
createBlockBlobFromStream(containerName, blobName, part, size, options, callback)
(если вам не нужны параметры, попробуйте пустой массив) для параметра.
Как ни странно, "параметры" должны быть факультативными, но по какой-то причине мой сбой не удастся, если я его оставлю.