web-dev-qa-db-ja.com

ノードjsを使用したS3ファイルアップロードストリーム

私は、要件のあるノードjsサーバーを使用してAmazon S3でファイルをストリーミングするためのソリューションを見つけようとしています。

  • サーバーまたはメモリに一時ファイルを保存しないでください。ただし、完全なファイルではなく、ある制限まで、バッファリングはアップロードに使用できます。
  • アップロードされるファイルのサイズに制限はありません。
  • ファイルのアップロードが完了すると、他のリクエストの待機時間が予想外に長くなるため、ファイルのアップロードが完了するまでサーバーをフリーズしないでください。

その場合、S3資格情報を共有する必要があるため、ブラウザーからの直接ファイルアップロードは使用しません。ノードjsサーバーからファイルをアップロードするもう1つの理由は、ファイルをアップロードする前に何らかの認証を適用する必要がある場合があることです。

Node-multipartyを使用してこれを達成しようとしました。しかし、期待どおりに機能していませんでした。私の解決策と問題は https://github.com/andrewrk/node-multiparty/issues/49 で確認できます。小さなファイルでは正常に動作しますが、サイズが15MBのファイルでは失敗します。

解決策や代替案はありますか?

27
Janak Kansal

nodejs用の公式Amazon SDK でストリーミングを使用できるようになりました。さらに素晴らしいことは、事前にファイルサイズを知らなくてもできることです。ストリームをBodyとして渡すだけです:

var fs = require('fs');
var zlib = require('zlib');

var body = fs.createReadStream('bigfile').pipe(zlib.createGzip());
var s3obj = new AWS.S3({params: {Bucket: 'myBucket', Key: 'myKey'}});
s3obj.upload({Body: body})
  .on('httpUploadProgress', function(evt) { console.log(evt); })
  .send(function(err, data) { console.log(err, data) });

https://www.npmjs.org/package/streaming-s を試してください。

いくつかの大きなファイルを並行して(> 500Mb)アップロードするために使用しましたが、非常にうまく機能しました。それは非常に構成可能で、アップロード統計を追跡することもできます。オブジェクトの合計サイズを知る必要はなく、ディスクには何も書き込まれません。

1

作業中のプロジェクトで s3-upload-stream モジュールを使用しています here

彼の http-framework リポジトリには@raynosの良い例もいくつかあります。

0
Daveee

または、- https://github.com/minio/minio-js をご覧ください。最も一般的に使用されるS3呼び出しを実装する抽象化されたAPIの最小限のセットがあります。

ストリーミングアップロードの例を次に示します。

$ npm install minio
$ cat >> put-object.js << EOF

var Minio = require('minio')
var fs = require('fs')

// find out your s3 end point here:
// http://docs.aws.Amazon.com/general/latest/gr/rande.html#s3_region

var s3Client = new Minio({
  url: 'https://<your-s3-endpoint>',
  accessKey: 'YOUR-ACCESSKEYID',
  secretKey: 'YOUR-SECRETACCESSKEY'
})

var outFile = fs.createWriteStream('your_localfile.Zip');
var fileStat = Fs.stat(file, function(e, stat) {
  if (e) {
    return console.log(e)
  }
  s3Client.putObject('mybucket', 'hello/remote_file.Zip', 'application/octet-stream', stat.size, fileStream, function(e) {
    return console.log(e) // should be null
  })
})
EOF

ここでputObject()は、5MBを超えるファイルサイズの完全に管理された単一関数呼び出しであり、内部で自動的にmultipartを実行します。失敗したアップロードも再開できます。以前にアップロードした部分を確認することにより、中断したところから開始します。

さらに、このライブラリも同型であり、ブラウザでも使用できます。

0
Harshavardhana

クライアントからs3に正常にストリーミングできた(メモリやディスクストレージなしで)ことができた場合:

https://Gist.github.com/mattlockyer/532291b6194f6d9ca40cb82564db9d2a

サーバーエンドポイントはreqがストリームオブジェクトであると想定します。クライアントからFileオブジェクトを送信し、これを最新のブラウザーがバイナリデータとして送信し、ヘッダーにファイル情報セットを追加しました。

const fileUploadStream = (req, res) => {
  //get "body" args from header
  const { id, fn } = JSON.parse(req.get('body'));
  const Key = id + '/' + fn; //upload to s3 folder "id" with filename === fn
  const params = {
    Key,
    Bucket: bucketName, //set somewhere
    Body: req, //req is a stream
  };
  s3.upload(params, (err, data) => {
    if (err) {
      res.send('Error Uploading Data: ' + JSON.stringify(err) + '\n' + JSON.stringify(err.stack));
    } else {
      res.send(Key);
    }
  });
};

はい、ヘッダーにファイル情報を入れると慣習に違反しますが、Gistを見ると、ストリーミングライブラリやmulter、busboyなどを使用して見つけた他のものよりもずっときれいです...

実用主義のために+1、そして彼の助けに@SalehenRahmanに感謝します。

0
mattdlockyer