13

我正在尝试使用 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 将二进制文件推送到 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()
            }
        });
    });
};

因此,为了将文件上传到 API 端点(使用 Node.js 和 Express)并让 API 将该文件推送到 Amazon S3,首先您需要执行 POST 请求并填充“文件”字段。该文件最终位于 API 端,它可能位于某个 tmp 目录中。Amazon 的 S3 putObject 方法需要 Stream,因此您需要通过为“fs”模块提供上传文件所在的路径来创建读取流。

我不知道这是否是上传数据的正确方法,但它有效。有谁知道是否有办法在请求正文中发布二进制数据并让 API 将其发送到 S3?我不太清楚多部分上传与标准 POST 到正文之间有什么区别。

4

1 回答 1

7

我相信您需要在标头中传递内容长度,如 S3 文档中所述: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;
    });

});

更新

因此,如果您使用的是基于 Formidable 构建的 Express 或 Connect,那么您无法访问文件流,因为 Formidable 会将文件写入磁盘。因此,根据您在客户端上传的方式,图像将位于req.bodyreq.files. 就我而言,我使用 Express,在客户端,我也发布其他数据,因此图像具有自己的参数并以req.files.img_data. 无论您如何访问它,该参数都是您img_path在上面的示例中传递的内容。

如果您需要/想要流式传输更棘手的文件,尽管肯定是可能的,并且如果您不处理图像,您可能希望考虑采用 CORS 方法并直接上传到 S3,如下所述:Stream that user uploads directly到亚马逊 s3

于 2013-09-26T00:34:41.687 回答