Empujando datos binarios a Amazon S3 usando Node.js

Estoy tratando de tomar una imagen y subirla a un depósito de Amazon S3 usando Node.js. Al final, quiero poder subir la imagen hasta S3, y luego poder acceder a esa URL S3 y ver la imagen en un navegador. Estoy usando una consulta Curl para hacer una solicitud HTTP POST con la imagen como cuerpo.

curl -kvX POST --data-binary "@test.jpg" 'http://localhost:3031/upload/image'

Luego en el lado de Node.js, hago esto:

 exports.pushImage = function(req, res) { var image = new Buffer(req.body); var s3bucket = new AWS.S3(); s3bucket.createBucket(function() { var params = {Bucket: 'My/bucket', Key: 'test.jpg', Body: image}; // Put the object into the bucket. s3bucket.putObject(params, function(err) { if (err) { res.writeHead(403, {'Content-Type':'text/plain'}); res.write("Error uploading data"); res.end() } else { res.writeHead(200, {'Content-Type':'text/plain'}); res.write("Success"); res.end() } }); }); }; 

Mi archivo es de 0 bytes, como se muestra en Amazon S3. ¿Cómo lo hago para que pueda usar Node.js para enviar el archivo binario a S3? ¿Qué estoy haciendo mal con los datos binarios y buffers?

ACTUALIZAR:

Descubrí lo que tenía que hacer. La consulta de rizo es lo primero que se debe cambiar. Este es el trabajo:

curl -kvX POST -F foobar=@my_image_name.jpg 'http://localhost:3031/upload/image'

Luego, agregué una línea para convertir a un Stream. Este es el código de trabajo:

 exports.pushImage = function(req, res) { var image = new Buffer(req.body); var s3bucket = new AWS.S3(); s3bucket.createBucket(function() { var bodyStream = fs.createReadStream(req.files.foobar.path); var params = {Bucket: 'My/bucket', Key: 'test.jpg', Body: bodyStream}; // Put the object into the bucket. s3bucket.putObject(params, function(err) { if (err) { res.writeHead(403, {'Content-Type':'text/plain'}); res.write("Error uploading data"); res.end() } else { res.writeHead(200, {'Content-Type':'text/plain'}); res.write("Success"); res.end() } }); }); }; 

Entonces, para cargar un archivo en un punto final de la API (utilizando Node.js y Express) y hacer que la API envíe ese archivo a Amazon S3, primero debe realizar una solicitud POST con el campo “archivos”. El archivo termina en el lado de la API, donde probablemente se encuentre en algún directorio tmp. El método putObject S3 de Amazon requiere una transmisión, por lo que necesita crear una transmisión de lectura al darle al módulo ‘fs’ la ruta donde existe el archivo cargado.

No sé si esta es la forma correcta de cargar datos, pero funciona. ¿Alguien sabe si hay una manera de POSTAR datos binarios dentro del cuerpo de la solicitud y hacer que la API lo envíe a S3? No sé muy bien cuál es la diferencia entre una carga de varias partes frente a un POST estándar para el cuerpo.

Creo que debe pasar la longitud del contenido en el encabezado como se documenta en los documentos de S3: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html

Después de pasar bastante tiempo trabajando en enviar activos a S3, terminé usando la biblioteca AwsSum con excelentes resultados en producción:

https://github.com/awssum/awssum-amazon-s3/

(Consulte la documentación sobre cómo configurar sus credenciales de AWS)

Ejemplo:

 var fs = require('fs'); var bucket_name = 'your-bucket name'; // AwsSum also has the API for this if you need to create the buckets var img_path = 'path_to_file'; var filename = 'your_new_filename'; // using stat to get the size to set contentLength fs.stat(img_path, function(err, file_info) { var bodyStream = fs.createReadStream( img_path ); var params = { BucketName : bucket_name, ObjectName : filename, ContentLength : file_info.size, Body : bodyStream }; s3.putObject(params, function(err, data) { if(err) //handle var aws_url = 'https://s3.amazonaws.com/' + DEFAULT_BUCKET + '/' + filename; }); }); 

ACTUALIZAR

Por lo tanto, si está utilizando algo como Express o Connect, que está construido en Formidable, entonces no tiene acceso a la secuencia de archivos como Formidable escribe los archivos en el disco. Entonces, dependiendo de cómo lo cargues en el lado del cliente, la imagen estará en req.body o req.files . En mi caso, uso Express y en el lado del cliente, también req.files.img_data otros datos para que la imagen tenga su propio parámetro y se acceda a ella como req.files.img_data . De cualquier forma que acceda, ese parámetro es lo que pasa como img_path en el ejemplo anterior.

Si necesita / desea Transmitir el archivo que es más complicado, aunque ciertamente es posible y si no está manipulando la imagen, puede considerar tomar un enfoque CORS y cargarlo directamente en S3 como se explica aquí: Transmitir las subidas de los usuarios directamente a Amazon s3