1. ホーム
  2. javascript

[解決済み] Node.jsでS3のgetObjectからレスポンスを取得する方法は?

2022-03-04 06:14:58

質問

Node.jsプロジェクトで、私はS3からデータを取得しようとしている。

を使用すると getSignedURL であれば、すべてうまくいきます。

aws.getSignedUrl('getObject', params, function(err, url){
    console.log(url); 
}); 

私のパラメータは

var params = {
              Bucket: "test-aws-imagery", 
              Key: "TILES/Level4/A3_B3_C2/A5_B67_C59_Tiles.par"

コンソールに出力されたURLをウェブブラウザに貼り付けると、必要なファイルがダウンロードされるんだ。

しかし、もし私が getObject いろいろと変な挙動になるんです。 使い方が間違っているだけだと思うのですが。 これは私が試したことです。

aws.getObject(params, function(err, data){
    console.log(data); 
    console.log(err); 
}); 

出力します。

{ 
  AcceptRanges: 'bytes',
  LastModified: 'Wed, 06 Apr 2016 20:04:02 GMT',
  ContentLength: '1602862',
  ETag: '9826l1e5725fbd52l88ge3f5v0c123a4"',
  ContentType: 'application/octet-stream',
  Metadata: {},
  Body: <Buffer 01 00 00 00  ... > }

  null

ということで、正常に動作しているように見えます。 しかし、ブレークポイントを console.log は、私のIDE(NetBeans)がエラーを投げ、データの値を表示することを拒否します。これはIDEだけの問題かもしれませんが、私は他の方法を試してみることにしました。 getObject .

aws.getObject(params).on('httpData', function(chunk){
    console.log(chunk); 
}).on('httpDone', function(data){
    console.log(data); 
});

これでは何も出力されません。 ブレークポイントを置くと、コードは決して console.log s. も試してみました。

aws.getObject(params).on('success', function(data){
    console.log(data); 
});

しかし、これも何も出力されないので、ブレークポイントを置くと console.log に到達することはありません。

何が間違っているのでしょうか?

どうすればいいですか?

を行う場合 getObject() につき、S3 APIから ドキュメント ファイルのコンテンツは Body プロパティを使用することができます。以下のようなコードになっているはずです。

const aws = require('aws-sdk');
const s3 = new aws.S3(); // Pass in opts to S3 if necessary

var getParams = {
    Bucket: 'abc', // your bucket name,
    Key: 'abc.txt' // path to the object you're looking for
}

s3.getObject(getParams, function(err, data) {
    // Handle any error and exit
    if (err)
        return err;

  // No error happened
  // Convert Body from a Buffer to a String
  let objectData = data.Body.toString('utf-8'); // Use the encoding necessary
});

から新しいバッファを作成する必要がない場合もあります。 data.Body オブジェクトがありますが、必要であれば、上記のサンプルを使って実現できます。

aws-sdk/client-s3 (2021年版)

2016年にこの回答を書いてから、Amazonは新しいJavaScript SDKをリリースしました。 @aws-sdk/client-s3 . この新しいバージョンは、オリジナルの getObject() によってオプトインする代わりに、常にプロミスを返すことによって .promise() に連鎖している。 getObject() . それに加えて response.Body は、もはや Buffer の1つですが Readable|ReadableStream|Blob . これは response.Data を少し。これは、すべての内容をメモリに保持する代わりに、返されたデータをストリームすることができるので、よりパフォーマンスが高くなるはずです。トレードオフとして、実装が少し冗長になります。

以下の例では response.Body のデータは配列にストリーミングされ、文字列として返されます。これは、私の最初の答えに相当する例です。あるいは response.Body を使用することができます。 stream.Readable.pipe() を HTTP レスポンスやファイル、その他あらゆるタイプの stream.Writeable を使用すると、大きなオブジェクトを取得する際に、よりパフォーマンスの高い方法となります。

を使いたい場合は Buffer のように、元の getObject() レスポンスで、これを行うには responseDataChunks の中に Buffer.concat() を使用する代わりに Array#join() これは、バイナリデータを扱うときに便利です。注意すべきは Array#join() は文字列を返すので、各 Buffer のインスタンスは responseDataChunks を持つことになります。 Buffer.toString() が暗黙のうちに呼び出され、デフォルトのエンコーディングである utf8 が使用されます。

const { GetObjectCommand, S3Client } = require('@aws-sdk/client-s3')
const client = new S3Client() // Pass in opts to S3 if necessary

function getObject (Bucket, Key) {
  return new Promise(async (resolve, reject) => {
    const getObjectCommand = new GetObjectCommand({ Bucket, Key })

    try {
      const response = await client.send(getObjectCommand)
  
      // Store all of data chunks returned from the response data stream 
      // into an array then use Array#join() to use the returned contents as a String
      let responseDataChunks = []

      // Handle an error while streaming the response body
      response.Body.once('error', err => reject(err))
  
      // Attach a 'data' listener to add the chunks of data to our array
      // Each chunk is a Buffer instance
      response.Body.on('data', chunk => responseDataChunks.push(chunk))
  
      // Once the stream has no more data, join the chunks into a string and return the string
      response.Body.once('end', () => resolve(responseDataChunks.join('')))
    } catch (err) {
      // Handle the error or throw
      return reject(err)
    } 
  })
}

@aws-sdk/client-s3 ドキュメントリンク