web-dev-qa-db-ja.com

Node.jsを使用してバイナリデータをAmazonS3にプッシュする

Node.jsを使用して、画像を取得し、AmazonS3バケットにアップロードしようとしています。最後に、画像を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()
            }
        });
    });
};

Amazon S3に示されているように、私のファイルは0バイトです。 Node.jsを使用してバイナリファイルをS3にプッシュできるようにするにはどうすればよいですか?バイナリデータとバッファで何が間違っていますか?

更新:

私は自分が何をする必要があるかを知りました。 curlクエリは、最初に変更する必要があるものです。これは機能しているものです:

curl -kvX POST -F foobar=@my_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リクエストを実行する必要があります。 「files」フィールドにデータが入力されます。ファイルはAPI側に配置され、おそらくtmpディレクトリにあります。AmazonのS3 putObjectメソッドにはStreamが必要なため、「fs」モジュールにパスを指定して読み取りストリームを作成する必要があります。アップロードされたファイルが存在します。

これがデータをアップロードする適切な方法かどうかはわかりませんが、機能します。リクエスト本文内にバイナリデータをPOSTして、APIにS3に送信させる方法があるかどうか誰かが知っていますか?マルチパートアップロードの違いはよくわかりませんvs標準POST本体へ。

13
Jack

S3ドキュメントに記載されているようにヘッダーにcontent-lengthを渡す必要があると思います: 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.bodyまたはreq.filesのいずれかになります。私の場合、Expressを使用し、クライアント側では他のデータも投稿するので、画像には独自のパラメーターがあり、req.files.img_dataとしてアクセスされます。どのようにアクセスしても、そのパラメータは上記の例でimg_pathとして渡すものです。

トリッキーなファイルをストリーミングする必要がある場合/ストリーミングしたい場合は確かに可能ですが、画像を操作していない場合は、ここで説明するように、CORSアプローチを採用してS3に直接アップロードすることを検討してください: StreamそのユーザーはAmazonに直接アップロードしますs

7
drivativ