使用Node.js将二进制数据推送到Amazon S3

我正在尝试使用Node.js将图像上传到Amazon S3存储桶。 最后,我希望能够将图像上传到S3,然后能够访问该S3 URL并在浏览器中查看图像。 我正在使用一个Curl查询来执行一个HTTP POST请求与图像作为正文。

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

然后在Node.js端,我这样做:

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

我的文件是0字节,如Amazon S3上所示。 我该如何使它能够使用Node.js将二进制file upload到S3? 我在做什么错误的二进制数据和缓冲区?

更新:

我发现我需要做什么。 curl查询是应该改变的第一件事。 这是工作的一个:

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

然后,我添加了一条线来转换成一个stream。 这是工作代码:

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

因此,为了将file upload到API端点(使用Node.js和Express)并使API将该文件推送到Amazon S3,首先需要填充“files”字段来执行POST请求。 该文件最终在API端,它可能位于某个tmp目录中。 Amazon的S3 putObject方法需要一个Stream,所以你需要通过给'fs'模块上传文件所在的path创build一个读stream。

我不知道这是否是正确的方式来上传数据,但它的工作原理。 有谁知道是否有一种方法来POST二进制数据内的请求正文,并有API发送到S3? 我不太清楚多部分上传与标准POST正文之间的区别。

我相信你需要传递在S3文档中logging的标头内容长度: http : //docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html

花了相当多的时间把资源推到S3上之后,我最终使用了AwsSum库,在生产中取得了很好的效果:

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

(请参阅有关设置AWS凭证的文档)

例:

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

UPDATE

因此,如果您使用的是Express或Connect这些构build在Formidable之上的东西,那么当Formidable将文件写入磁盘时,您无法访问文件stream。 所以根据你在客户端的上传方式,图像将会在req.bodyreq.files 。 在我的情况下,我使用Express,在客户端,我也发布其他数据,所以图像有它自己的参数,并作为req.files.img_data访问。 但是你可以访问它,这个参数就是你在上面例子中作为img_path传入的参数。

如果您需要/想要stream式处理更棘手的文件,虽然当然可以,如果您不操作图像,您可能需要考虑采用CORS方法并直接上传到S3,如下所述: 直接stream式传输用户上传到亚马逊S3