subir proyecto node crear archivos node.js express amazon-s3 aws-sdk

node.js - proyecto - express router get params



TransmisiĆ³n de archivos desde S3 con Express, incluida informaciĆ³n sobre la longitud y el tipo de archivo (3)

Usando el módulo aws-sdk y Express 4.13, es posible hacer proxy de un archivo desde S3 de varias maneras.

Esta versión de devolución de llamada devolverá el cuerpo del archivo como un búfer, además de otros encabezados relevantes como Content-Length :

function(req,res){ var s3 = new AWS.S3(); s3.getObject({Bucket: myBucket, Key: myFile},function(err,data){ if (err) { return res.status(500).send("Error!"); } // Headers res.set("Content-Length",data.ContentLength) .set("Content-Type",data.ContentType); res.send(data.Body); // data.Body is a buffer }); }

El problema con esta versión es que debes obtener el archivo completo antes de enviarlo, lo cual no es bueno, especialmente si es algo grande como un video.

Esta versión transmitirá directamente el archivo:

function(req,res){ var s3 = new AWS.S3(); s3.getObject({Bucket: myBucket, Key: myFile}) .createReadStream() .pipe(res); }

Pero a diferencia del primero, no hará nada con los encabezados, que un navegador puede necesitar para manejar el archivo correctamente.

¿Hay alguna forma de obtener lo mejor de ambos mundos, pasando por los encabezados correctos desde S3 pero enviando el archivo como una transmisión? Se podría hacer haciendo primero una solicitud HEAD a S3 para obtener los metadatos, pero ¿se puede hacer con una llamada a la API?


Para mi proyecto, simplemente hago un headObject para recuperar solo los metadatos del objeto (es muy rápido y evita descargar el objeto). Luego agrego en la respuesta todos los encabezados que necesito para propagar para la tubería:

var s3 = new AWS.S3(); var params = { Bucket: bucket, Key: key }; s3.headObject(params, function (err, data) { if (err) { // an error occurred console.error(err); return next(); } var stream = s3.getObject(params).createReadStream(); // forward errors stream.on(''error'', function error(err) { //continue to the next middlewares return next(); }); //Add the content type to the response (it''s not propagated from the S3 SDK) res.set(''Content-Type'', mime.lookup(key)); res.set(''Content-Length'', data.ContentLength); res.set(''Last-Modified'', data.LastModified); res.set(''ETag'', data.ETag); stream.on(''end'', () => { console.log(''Served by Amazon S3: '' + key); }); //Pipe the s3 object to the response stream.pipe(res); });


Sobre la base de la respuesta de André Werlang, hemos hecho lo siguiente para aumentar los objetos de Request AWS con un método forwardToExpress :

const _ = require(''lodash''); const AWS = require(''aws-sdk''); AWS.Request.prototype.forwardToExpress = function forwardToExpress(res, next) { this .on(''httpHeaders'', function (code, headers) { if (code < 300) { res.set(_.pick(headers, ''content-type'', ''content-length'', ''last-modified'')); } }) .createReadStream() .on(''error'', next) .pipe(res); };

Luego, en nuestros manejadores de ruta, podemos hacer algo como esto:

s3.getObject({Bucket: myBucket, Key: myFile}).forwardToExpress(res, next);


Un enfoque es escuchar el evento httpHeaders y crear un flujo dentro de él.

s3.getObject(params) .on(''httpHeaders'', function (statusCode, headers) { res.set(''Content-Length'', headers[''content-length'']); res.set(''Content-Type'', headers[''content-type'']); this.response.httpResponse.createUnbufferedStream() .pipe(res); }) .send();