Нажатие двоичных данных на Amazon S3 с помощью Node.js

Я пытаюсь взять изображение и загрузить его в ведро Amazon S3 с помощью Node.js. В конце концов, я хочу, чтобы можно было поднять изображение до S3, а затем получить доступ к этому URL-адресу S3 и увидеть изображение в браузере. Я использую запрос 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? Что я делаю неправильно с двоичными данными и буферами?

UPDATE:

Я узнал, что мне нужно делать. Запрос curl - это первое, что нужно изменить. Это рабочий:

curl -kvX POST -F [email protected]_image_name.jpg 'http://localhost:3031/upload/image'

Затем я добавил строку для преобразования в поток. Это рабочий код:

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 требуется поток, поэтому вам нужно создать поток чтения, предоставив модулю "fs" путь, в котором находится загруженный файл.

Я не знаю, подходит ли это для загрузки данных, но он работает. Кто-нибудь знает, есть ли способ получить двоичные данные POST внутри тела запроса и отправить API на S3? Я не совсем понимаю, какая разница между многочастной загрузкой и стандартным POST для тела.

Ответ 1

Я считаю, что вам нужно передать длину контента в заголовке, как описано в документах 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;
    });

});

ОБНОВЛЕНИЕ

Итак, если вы используете что-то вроде Express или Connect, которые построены на Formidable, тогда у вас нет доступа к файловому потоку, поскольку Formidable записывает файлы на диск. Поэтому в зависимости от того, как вы загружаете его на стороне клиента, изображение будет либо в req.body, либо req.files. В моем случае я использую Express и на стороне клиента, я отправляю другие данные, так что у изображения есть свой собственный параметр и доступен как req.files.img_data. Однако вы обращаетесь к нему, этот параметр - это то, что вы передаете как img_path в приведенном выше примере.

Если вам нужно/нужно Стрить файл, который сложнее, но, конечно, возможно, и если вы не манипулируете изображением, вы можете захотеть взглянуть на подход CORS и загрузить непосредственно на S3, как описано здесь: Поток, который пользователь загружает непосредственно в Amazon s3