Transmita el archivo cargado al almacenamiento de blobs de Azure con Node

Con Express with Node, puedo cargar un archivo con éxito y pasarlo al almacenamiento de Azure en el siguiente bloque de código.

app.get('/upload', function (req, res) { res.send( '' + '' + '' + '' ); }); 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"); }); 

Esto funciona bien, pero Express crea un archivo temporal y primero almacena la imagen, luego la subo a Azure desde el archivo. Esto parece un paso ineficiente e innecesario en el proceso y acabo teniendo que gestionar la limpieza del directorio del archivo temporal.

Debería poder transmitir el archivo directamente al almacenamiento de Azure utilizando el método blobService.createBlockBlobFromStream en el SDK de Azure, pero no estoy lo suficientemente familiarizado con Node o Express para entender cómo acceder a los datos de transmisión.

 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"); }); 

He encontrado el siguiente blog que indica que puede haber una forma de hacerlo, y ciertamente Express está tomando los datos de la transmisión y analizándolos y guardándolos también en el sistema de archivos. http://blog.valeryjacobs.com/index.php/streaming-media-from-url-to-blob-storage/

El código de vjacobs es en realidad descargar un archivo de otro sitio y pasar esa transmisión a Azure, por lo que no estoy seguro de que pueda adaptarse a mi situación.

¿Cómo puedo acceder y pasar la transmisión de archivos cargados directamente a Azure usando Node?

SOLUCIÓN (basada en la discusión con @danielepolencic)

Usando Multiparty (npm install multiparty), una bifurcación de Formidable, podemos acceder a los datos de varias partes si deshabilitamos el middleware bodyparser () de Express (consulte sus notas sobre cómo hacer esto para obtener más información). A diferencia de Formidable, Multiparty no transmitirá el archivo al disco a menos que usted lo indique.

 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'); }); 

Atrezzo a @danielepolencic por ayudar a encontrar la solución a esto.

Como puede leer en la documentación de middleware de bodyparser , bodyparser maneja bodyparser el formulario por usted. En su caso particular, analiza los datos de req.files partes entrantes y los almacena en otro lugar, luego expone el archivo guardado en un formato agradable (es decir, req.files ).

Desafortunadamente, no necesitamos (y necesitamos) magia negra principalmente porque queremos poder transmitir los datos entrantes a Azure directamente sin golpear el disco (es decir, req.pipe(res) ). Por lo tanto, podemos desactivar el middleware bodyparser y manejar la solicitud entrante nosotros mismos. Bajo el capó, bodyparser usa bodyparser formidables , por lo que puede ser una buena idea reutilizarlo en nuestra implementación.

 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( '
' + '' + '' + '
' ); }); 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);

La idea central es que podemos aprovechar los flujos de nodos para que no tengamos que cargar en la memoria el archivo completo antes de poder enviarlo a Azure, pero podemos transferirlo a medida que se presente. El módulo formidable de nodos admite flujos, por lo tanto, canalizar el flujo hacia el azul alcanzará nuestro objective.

Puede probar fácilmente el código localmente sin golpear el azul reemplazando la ruta de post con:

 app.post('/upload', function (req, res) { var form = new formidable.IncomingForm(); form.onPart = function(part){ part.pipe(res); }; form.parse(req); }); 

Aquí, simplemente estamos canalizando la solicitud de la entrada a la salida. Puedes leer más sobre bodyParser aquí .

Existen diferentes opciones para cargar datos binarios (por ejemplo, imágenes) a través del SDK de almacenamiento de Azure para el nodo, sin usar varias partes.

Basándose en las definiciones de Buffer y Stream en Node y manipulándolas, se podrían manejar usando casi todos los métodos para subir BLOB: createWriteStreamToBlockBlob , createBlockBlobFromStream , createBlockBlobFromText .

Las referencias se pueden encontrar aquí: Cargar datos binarios desde el cuerpo de la solicitud al almacenamiento de BLOB de Azure en Node.js [restify]

Las personas que tienen problemas con .createBlockBlobFromStream que intenta implementar las soluciones, deben tener en cuenta que este método ha cambiado ligeramente en las versiones más nuevas.

Versión antigua:

 createBlockBlobFromStream(containerName, blobName, part, size, callback) 

Nueva versión

 createBlockBlobFromStream(containerName, blobName, part, size, options, callback) 

(Si no te importan las opciones, prueba una matriz vacía) para el parámetro.

Por extraño que parezca, se supone que las “opciones” son opcionales, pero por alguna razón, la mía falla si la dejo fuera.