web-dev-qa-db-ja.com

空のファイルを生成するボディストリームを含むJavaScript AWS SDK S3アップロードメソッド

ReadableStreamを使用してs3からメソッドuploadを使用しようとしていますモジュールfsから。

documentation は、ReadableStreamをBodyparamで使用できることを示しています。

本文—(バッファ、型付き配列、Blob、文字列、ReadableStream)オブジェクトデータ。

また、uploadメソッドの説明は次のとおりです。

ペイロードが十分に大きい場合、パーツのインテリジェントな同時処理を使用して、任意のサイズのバッファ、BLOB、またはストリームをアップロードします。

また、ここ: nodejs aws sdkを使用してAWS S3に生成されたPDFをアップロード @shivendraは、ReadableStreamを使用でき、それが機能することを示しています。

これは私のコードです:

const fs = require('fs')
const S3 = require('aws-sdk/clients/s3')

const s3 = new S3()

const send = async () => {
  const rs = fs.createReadStream('/home/osman/Downloads/input.txt')
  rs.on('open', () => {
    console.log('OPEN')
  })
  rs.on('end', () => {
    console.log('END')
  })
  rs.on('close', () => {
    console.log('CLOSE')
  })
  rs.on('data', (chunk) => {
    console.log('DATA: ', chunk)
  })

  console.log('START UPLOAD')

  const response = await s3.upload({
    Bucket: 'test-bucket',
    Key: 'output.txt',
    Body: rs,
  }).promise()

  console.log('response:')
  console.log(response)
}

send().catch(err => { console.log(err) })

この出力を取得しています:

START UPLOAD
OPEN
DATA: <Buffer 73 6f 6d 65 74 68 69 6e 67>
END
CLOSE
response:
{ ETag: '"d41d8cd98f00b204e9800998ecf8427e"',
  Location: 'https://test-bucket.s3.amazonaws.com/output.txt',
  key: 'output.txt',
  Key: 'output.txt',
  Bucket: 'test-bucket' }

問題は、S3で生成されたファイル(output.txt)のバイト数が0であることです。

誰かが私が間違っていることを知っていますか?

Bodyにバッファを渡すと機能します。

Body: Buffer.alloc(8 * 1024 * 1024, 'something'), 

しかし、それは私がやりたいことではありません。ストリームを使用してこれを行い、ファイルを生成して、ストリームを生成する限り、S3にパイプします。

10
osmanpontes

これは、NodeJS ReadableStreamsを使用したAPIインターフェースの問題です。リスニングイベント_'data'_に関連するコードをコメント化するだけで、問題が解決します。

_const fs = require('fs')
const S3 = require('aws-sdk/clients/s3')

const s3 = new S3()

const send = async () => {
  const rs = fs.createReadStream('/home/osman/Downloads/input.txt')
  rs.on('open', () => {
    console.log('OPEN')
  })
  rs.on('end', () => {
    console.log('END')
  })
  rs.on('close', () => {
    console.log('CLOSE')
  })
  // rs.on('data', (chunk) => {
  //   console.log('DATA: ', chunk)
  // })

  console.log('START UPLOAD')

  const response = await s3.upload({
    Bucket: 'test-bucket',
    Key: 'output.txt',
    Body: rs,
  }).promise()

  console.log('response:')
  console.log(response)
}

send().catch(err => { console.log(err) })
_

奇妙なAPIですが、_'data'_イベントをリッスンすると、ReadableStreamflowingモードを開始します(パブリッシャー/ EventEmitterの状態を変更するイベントをリッスンしますか?はい、非常にエラー起こりやすい...)。何らかの理由でS3には一時停止ReadableStreamが必要です。 rs.on('data'...)の後にawait s3.upload(...)を置いた場合、機能します。 rs.pause()の後にrs.on('data'...)を置き、await s3.upload(...)を後置しても機能します。

さて、それはどうなりますか?まだわかりません...

しかし、完全に説明されていなくても、問題は解決されました。

18
osmanpontes
  1. ファイル/home/osman/Downloads/input.txtが実際に存在し、node.jsプロセスでアクセスできるかどうかを確認します
  2. putObject メソッドの使用を検討してください

例:

const fs = require('fs');
const S3 = require('aws-sdk/clients/s3');

const s3 = new S3();

s3.putObject({
  Bucket: 'test-bucket',
  Key: 'output.txt',
  Body: fs.createReadStream('/home/osman/Downloads/input.txt'),
}, (err, response) => {
  if (err) {
    throw err;
  }
  console.log('response:')
  console.log(response)
});

これがasync .. awaitでどのように機能するかわからないため、AWS:S3へのアップロードを最初に機能させてから、フローを変更することをお勧めします。


更新: ManagedUpload を介して直接アップロードを実装してみてください

const fs = require('fs');
const S3 = require('aws-sdk/clients/s3');

const s3 = new S3();

const upload = new S3.ManagedUpload({
  service: s3,
  params: {
    Bucket: 'test-bucket',
    Key: 'output.txt',
    Body: fs.createReadStream('/home/osman/Downloads/input.txt')
  }
});

upload.send((err, response) => {
  if (err) {
    throw err;
  }
  console.log('response:')
  console.log(response)
});
1
dr.dimitru