programing

Node.js에서 S3 getObject의 응답을 얻는 방법은?

javajsp 2023. 9. 11. 21:28

Node.js에서 S3 getObject의 응답을 얻는 방법은?

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저는 온갖 이상한 행동을 합니다.제가 잘못 사용하고 있는 것 같습니다.제가입니다:이가한다다한s가:이istd' .

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

그래서 이게 제대로 작동하는 것 같습니다.만 중 때가에을때을중그때r을을nfina가etk에e,t,만console.log 내 시키고 data, IDE(NetBeans) 를 시키고 합니다 를 을 는 합니다 를 을 시키고 를 는 IDE일 , 는 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도달하지 않습니다.

내가 뭘 잘못하고 있는 거지?

@aws-sdk/client-s3 (2022 업데이트)

제가 2016년에 이 답변을 작성한 이후, 아마존은 새로운 자바스크립트 SDK를 출시했습니다. 이 새로운 버전은 원본보다 개선되었습니다.getObject()을 통해 으로써..promise()쇠사슬에 묶인 채getObject(). 그 외에도, 더 이상 a가 아니라,Readable|ReadableStream|Blob . 로 가 됩니다 의 가 변경됩니다.response.Data약간. 이것은 모든 내용을 메모리에 저장하는 대신 반환된 데이터를 스트리밍할 수 있기 때문에 더욱 성능이 뛰어나야 하며, 구현하기에는 좀 더 포괄적이라는 절충점이 있습니다.

에서는 의 에서 에서 의.response.Body데이터가 배열로 스트리밍된 다음 문자열로 반환됩니다.이것은 나의 원래 답변에 해당하는 예시입니다.는은.response.BodyHTTP 응답, 파일 또는 다른 유형의 다른 사용에 사용할 수 있습니다. 이것은 큰 객체를 얻을 때 더 성능적인 방법이 될 것입니다.

만약 당신이 a를 사용하고 싶다면.BuffergetObject(),은로할수다다수g할eey,답e로n,은s responseDataChunks를 사용하는 대신 이진 데이터와 상호 작용할 때 유용합니다.참고로, 그 이후로Array#join()을합니다 ).BufferresponseDataChunks은연중에 호출될 것이고 기본 인코딩은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)
    } 
  })
}

사용에 대한 Readable.toArray()

스트림 이벤트를 직접 사용하는 대신 사용하는 것이 더 편리할 수 있지만 성능이 더 좋지 않습니다.다음 단계로 넘어가기 전에 모든 응답 데이터 청크를 메모리로 읽음으로써 작동합니다.이렇게 하면 스트리밍의 모든 이점이 제거되므로 Node.js 문서에 따라 이러한 접근 방식을 사용할 수 없습니다.

이 방법은 전체 스트림을 메모리로 읽어 들이기 때문에 스트림의 이점을 부정합니다.이것은 상호운용성과 편리성을 목적으로 하는 것이지 스트림을 소비하는 주요 방법이 아닙니다.설명서 링크

@aws-sdk/client-s3 Links서

aws-sdk (Original Answs-sdk

을 할 때.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 하지만 하여 그것을할 수 . object면의을여을할다수만다수t할ttt만ee을foen

@을 토대로 @peteb의 에를 사용하면 에 하여 .Promises그리고.Async/Await:

const AWS = require('aws-sdk');

const s3 = new AWS.S3();

async function getObject (bucket, objectKey) {
  try {
    const params = {
      Bucket: bucket,
      Key: objectKey 
    }

    const data = await s3.getObject(params).promise();

    return data.Body.toString('utf-8');
  } catch (e) {
    throw new Error(`Could not retrieve file from S3: ${e.message}`)
  }
}

// To retrieve you need to use `await getObject()` or `getObject().then()`
const myObject = await getObject('my-bucket', 'path/to/the/object.txt');

업데이트됨(2022)

nodejs v17.5.0이 Readable.을 Array에 추가했습니다.노드 버전에서 이 API를 사용할 수 있는 경우.코드는 매우 짧습니다.

const buffer = Buffer.concat(
    await (
        await s3Client
            .send(new GetObjectCommand({
                Key: '<key>',
                Bucket: '<bucket>',
            }))
    ).Body.toArray()
)

Typcript 하는 을 해도 합니다 를 합니다 해도 하는 을 를.Body로서 헤어지다Readable 유형타형)ReadableStream그리고.Blob브라우저 환경에서만 반환됩니다.Blob 지원되지 않는 경우 레거시 페치 API에서만 사용됨)

(response.Body as Readable).toArray()

:Readable.toArray는 실험적인(그러나 편리한) 기능이므로 주의하여 사용하십시오.

enter image description here

=============

원답

aws sdk v3을 사용하는 경우 sdk v3는 버퍼 대신 nodejs Readable(정확히는 Readable을 확장하는 Incoming Message)을 반환합니다.

다음은 Typescript 버전입니다.노드 전용이므로 브라우저에서 요청을 보낸 경우 아래에 언급된 블로그 게시물에서 더 긴 답변을 확인하십시오.

import {GetObjectCommand, S3Client} from '@aws-sdk/client-s3'
import type {Readable} from 'stream'

const s3Client = new S3Client({
    apiVersion: '2006-03-01',
    region: 'us-west-2',
    credentials: {
        accessKeyId: '<access key>',
        secretAccessKey: '<access secret>',
    }
})
const response = await s3Client
    .send(new GetObjectCommand({
        Key: '<key>',
        Bucket: '<bucket>',
    }))
const stream = response.Body as Readable

return new Promise<Buffer>((resolve, reject) => {
    const chunks: Buffer[] = []
    stream.on('data', chunk => chunks.push(chunk))
    stream.once('end', () => resolve(Buffer.concat(chunks)))
    stream.once('error', reject)
})
// if readable.toArray() is support
// return Buffer.concat(await stream.toArray())

왜 캐스팅을 해야 합니까?response.Body as Readable? 답이 너무 깁니다.관심 있는 독자들은 제 블로그 포스트에서 더 많은 정보를 찾을 수 있습니다.

어떤 사람이 당신을 찾는 것을NEST JS TYPESCRIPT:위전:

    /**
     * to fetch a signed URL of a file
     * @param key key of the file to be fetched
     * @param bucket name of the bucket containing the file
     */
    public getFileUrl(key: string, bucket?: string): Promise<string> {
        var scopeBucket: string = bucket ? bucket : this.defaultBucket;
        var params: any = {
            Bucket: scopeBucket,
            Key: key,
            Expires: signatureTimeout  // const value: 30
        };
        return this.account.getSignedUrlPromise(getSignedUrlObject, params);
    }

    /**
     * to get the downloadable file buffer of the file
     * @param key key of the file to be fetched
     * @param bucket name of the bucket containing the file
     */
    public async getFileBuffer(key: string, bucket?: string): Promise<Buffer> {
        var scopeBucket: string = bucket ? bucket : this.defaultBucket;
        var params: GetObjectRequest = {
            Bucket: scopeBucket,
            Key: key
        };
        var fileObject: GetObjectOutput = await this.account.getObject(params).promise();
        return Buffer.from(fileObject.Body.toString());
    }

    /**
     * to upload a file stream onto AWS S3
     * @param stream file buffer to be uploaded
     * @param key key of the file to be uploaded
     * @param bucket name of the bucket 
     */
    public async saveFile(file: Buffer, key: string, bucket?: string): Promise<any> {
        var scopeBucket: string = bucket ? bucket : this.defaultBucket;
        var params: any = {
            Body: file,
            Bucket: scopeBucket,
            Key: key,
            ACL: 'private'
        };
        var uploaded: any = await this.account.upload(params).promise();
        if (uploaded && uploaded.Location && uploaded.Bucket === scopeBucket && uploaded.Key === key)
            return uploaded;
        else {
            throw new HttpException("Error occurred while uploading a file stream", HttpStatus.BAD_REQUEST);
        }
    }

GetObjectOutput.BodyPromise<string> 변환 사용

aws-sdk-js-v3 @aws-sdk/client-s3에서 는 aws-sdk v2에서와 같이 a가 아닌 in nodejs(특히 의 인스턴스)의 하위 클래스이므로resp.Body.toString('utf-8')잘못된 결과를 제공합니다. "[object Object]".에,장,수를 바꾸는 가장 쉬운 방법.GetObjectOutput.BodyPromise<string>노드-모듈을 구성하는 것이고, 이것은 다음을 필요로 합니다.Readable 클래스스)Bufferinstance, 또는 fetch spec의 다른 유형) 및 변환 방법이 있습니다..json(),.text(),.arrayBuffer(),그리고..blob().

node 는 aws-sdk 해야 에서도 의 에서도 해야 Buffer, v3 Uint8Array 클래스,스, v2드Readable, v2 ReadableStream아니면Blob)

npm install node-fetch
import { Response } from 'node-fetch';
import * as s3 from '@aws-sdk/client-s3';

const client = new s3.S3Client({})
const s3Response = await client.send(new s3.GetObjectCommand({Bucket: '…', Key: '…'});
const response = new Response(s3Response.Body);

const obj = await response.json();
// or
const text = await response.text();
// or
const buffer = Buffer.from(await response.arrayBuffer());
// or
const blob = await response.blob();

참조: 설명서, 노드-페치 설명서, 노드-페치 컨스트럭터 소스, 미니패스-페치 컨스트럭터 소스

사용성 이슈에 대한 kennu의 코멘트 덕분입니다.

위의 @ArianAcosta와 매우 유사한 답변입니다.제가 사용하고 있는 것을 제외하고는import 12), 구성 추가 및 페이로드에 및 (Node 12.x의), AWS성가및지용에및핑한우용(및핑rbase64한리e한o에se로 처리return.

// using v2.x of aws-sdk
import aws from 'aws-sdk'

aws.config.update({
  accessKeyId: process.env.YOUR_AWS_ACCESS_KEY_ID,
  secretAccessKey: process.env.YOUR_AWS_SECRET_ACCESS_KEY,
  region: "us-east-1" // or whatever
})

const s3 = new aws.S3();

/**
 * getS3Object()
 * 
 * @param { string } bucket - the name of your bucket
 * @param { string } objectKey - object you are trying to retrieve
 * @returns { string } - data, formatted
 */
export async function getS3Object (bucket, objectKey) {
  try {
    const params = {
      Bucket: bucket,
      Key: objectKey 
    }

    const data = await s3.getObject(params).promise();

    // Check for image payload and formats appropriately
    if( data.ContentType === 'image/jpeg' ) {
      return data.Body.toString('base64');
    } else {
      return data.Body.toString('utf-8');
    }

  } catch (e) {
    throw new Error(`Could not retrieve file from S3: ${e.message}`)
  }
}

언뜻 보기에는 당신이 잘못하고 있는 것 같지는 않지만 당신의 코드를 모두 보여주지는 않습니다.S3와 Node를 처음 체크아웃할 때는 다음과 같은 것이 효과가 있었습니다.

var AWS = require('aws-sdk');

if (typeof process.env.API_KEY == 'undefined') {
    var config = require('./config.json');
    for (var key in config) {
        if (config.hasOwnProperty(key)) process.env[key] = config[key];
    }
}

var s3 = new AWS.S3({accessKeyId: process.env.AWS_ID, secretAccessKey:process.env.AWS_KEY});
var objectPath = process.env.AWS_S3_FOLDER +'/test.xml';
s3.putObject({
    Bucket: process.env.AWS_S3_BUCKET, 
    Key: objectPath,
    Body: "<rss><data>hello Fred</data></rss>",
    ACL:'public-read'
}, function(err, data){
    if (err) console.log(err, err.stack); // an error occurred
    else {
        console.log(data);           // successful response
        s3.getObject({
            Bucket: process.env.AWS_S3_BUCKET, 
            Key: objectPath
        }, function(err, data){
            console.log(data.Body.toString());
        });
    }
});

또는 minio-js 클라이언트 라이브러리 get-object.js를 사용할 수 있습니다.

var Minio = require('minio')

var s3Client = new Minio({
  endPoint: 's3.amazonaws.com',
  accessKey: 'YOUR-ACCESSKEYID',
  secretKey: 'YOUR-SECRETACCESSKEY'
})

var size = 0
// Get a full object.
s3Client.getObject('my-bucketname', 'my-objectname', function(e, dataStream) {
  if (e) {
    return console.log(e)
  }
  dataStream.on('data', function(chunk) {
    size += chunk.length
  })
  dataStream.on('end', function() {
    console.log("End. Total size = " + size)
  })
  dataStream.on('error', function(e) {
    console.log(e)
  })
})

면책 사항:저는 자바, 파이썬, Js, golang에서 사용 가능한 클라이언트 라이브러리와 함께 golang으로 작성된 minio Its의 오픈 소스, S3 호환 객체 스토리지에서 일하고 있습니다.

대체 솔루션으로서:

같은 주제의 이 문제에 따르면, 2022년 10월에 S3 GetObject 요청에서 반송된 바디를 처리하는 방법이 있을 것 같습니다.AWS SDK V3를 사용한다고 가정하면@aws-sdk/util-stream-nodepackage:의 AWS SDK지:

import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { sdkStreamMixin } from '@aws-sdk/util-stream-node';

const s3Client = new S3Client({});
const { Body } = await s3Client.send(
  new GetObjectCommand({
    Bucket: 'your-bucket',
    Key: 'your-key',
  }),
);

// Throws error if Body is undefined
const body = await sdkStreamMixin(Body).transformToString();

으로 할 할 을 사용하여 본문을 바이트 배열 또는 웹 스트림으로 변환할 수 있습니다..transformToByteArray()그리고..transformToWebStream()기능들.

패키지에는 직접 사용해서는 안 된다고 되어 있지만, 요청에 따라 가장 간단한 신체 처리 방법인 것 같습니다.

이는 이 기능을 추가한 PR을 강조한 회신에서 확인할 수 있었습니다.

Body.toString() 메서드는 최신 버전의 s3 api에서 더 이상 작동하지 않습니다.대신 다음을 사용합니다.

const { S3Client, GetObjectCommand } = require("@aws-sdk/client-s3");

const streamToString = (stream) =>
    new Promise((resolve, reject) => {
      const chunks = [];
      stream.on("data", (chunk) => chunks.push(chunk));
      stream.on("error", reject);
      stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
    });

(async () => {
  const region = "us-west-2";
  const client = new S3Client({ region });

  const command = new GetObjectCommand({
    Bucket: "test-aws-sdk-js-1877",
    Key: "readme.txt",
  });

  const { Body } = await client.send(command);
  const bodyContents = await streamToString(Body);
  console.log(bodyContents);
})();

여기서 복사하여 붙여넣기: https://github.com/aws/aws-sdk-js-v3/issues/1877#issuecomment-755387549

왜 이 솔루션이 아직 추가되지 않았는지 잘 모르겠습니다. 제 생각에는 상위 답변보다 더 깨끗합니다.

이 솔루션은 aws-sdk v3 버전을 위한 것입니다.

json에서 s3 응답이 필요한 경우 다음 솔루션을 사용해 볼 수 있습니다.

const { GetObjectCommand, S3Client } = require("@aws-sdk/client-s3");
const s3 = new S3Client({});


async function getS3Config() {
    const params = {
        Bucket: "abc_bucket",
        Key: 'sample.json'
    }

    try {
        const command = new GetObjectCommand(params);
        const { Body } = await s3.send(command);
        let result = await streamToString(Body);
        result = JSON.parse(result);
        return result;
    } catch (err) {
        console.error(err);
    }
}



const streamToString = (stream) => new Promise((resolve, reject) => {
    const chunks = [];
    stream.on('data', (chunk) => chunks.push(chunk));
    stream.on('error', reject);
    stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
});

streamToString 기능은 응답이 완료되면 스트림을 청크 및 concat로 변환하는 기능입니다.

새 버전의 SDK 및 유형 스크립트 사용

const params = {
                Bucket: bucketName,
                Key: item.Key
            }

            s3.send(new GetObjectCommand(params))
                .then(async data => {
                    fs.writeFileSync(`./${folderName}/${item.Key?.split('/').pop()}`, await data.Body!.transformToString('utf-8'))
                })
                .catch(err => {
                    console.log(err)
                })

가 입니다.async/await

var getObjectAsync = async function(bucket,key) {
  try {
    const data = await s3
      .getObject({ Bucket: bucket, Key: key })
      .promise();
      var contents = data.Body.toString('utf-8');
      return contents;
  } catch (err) {
    console.log(err);
  }
}
var getObject = async function(bucket,key) {
    const contents = await getObjectAsync(bucket,key);
    console.log(contents.length);
    return contents;
}
getObject(bucket,key);

express 및 AWS SDK v3 사용:

  public downloadFeedFile = (req: IFeedUrlRequest, res: Response) => {
    const downloadParams: GetObjectCommandInput = parseS3Url(req.s3FileUrl.replace(/\s/g, ''));
    logger.info("requesting S3 file  " + JSON.stringify(downloadParams));
    const run = async () => {
      try {
        const fileStream = await this.s3Client.send(new GetObjectCommand(downloadParams));
        if (fileStream.Body instanceof Readable){
          fileStream.Body.once('error', err => {
            console.error("Error downloading s3 file")
            console.error(err);
          });

          fileStream.Body.pipe(res);

        }
      } catch (err) {
        logger.error("Error", err);
      }
    };

  run();

  };

언급URL : https://stackoverflow.com/questions/36942442/how-to-get-response-from-s3-getobject-in-node-js