จะรับการตอบสนองจาก S3 getObject ใน Node.js ได้อย่างไร


90

ในโปรเจ็กต์ 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.logs IDE (NetBeans) ของฉันจะแสดงข้อผิดพลาดและปฏิเสธที่จะแสดงค่าของข้อมูล ในขณะนี้ก็อาจจะเป็น IDE getObjectที่ฉันตัดสินใจที่จะลองวิธีอื่นในการใช้งาน

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

สิ่งนี้ไม่ส่งผลอะไรเลย การใส่เบรกพอยต์แสดงว่าโค้ดไม่ไปถึงconsole.logs อย่างใดอย่างหนึ่ง ฉันยังลอง:

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

อย่างไรก็ตามสิ่งนี้ยังไม่ส่งออกอะไรและการวางเบรกพอยต์แสดงว่าconsole.logไม่ถึงจุด

ผมทำอะไรผิดหรือเปล่า?


awsวัตถุของคุณเป็นตัวอย่างใหม่ของaws.S3วัตถุหรือไม่? นอกจากนี้การตอบสนองจากgetObject()การส่งกลับไปยังการตอบกลับ http หรือกำลังถูกส่งไปยังไฟล์?
peteb

@peteb aws = new AWS.S3(). ไม่ควรส่งการตอบกลับไปยังไฟล์ ฉันจำเป็นต้องใช้ใน Javascript
Sara Tibbetts

ดังนั้นจึงปลอดภัยที่จะสมมติว่าเนื้อหาเป็น JSON หรือ XML?
peteb

@peteb ไม่ใช่รูปแบบไฟล์ที่กำหนดเอง
Sara Tibbetts

แสดงพารามิเตอร์ที่คุณใช้ในการgetObject()โทร หากคุณพยายามส่ง URL ที่ลงชื่อไปยัง getObject ฉันไม่คิดว่าจะได้ผล
Mark B

คำตอบ:


178

เมื่อทำ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ออบเจ็กต์ แต่ถ้าคุณต้องการคุณสามารถใช้ตัวอย่างด้านบนเพื่อบรรลุเป้าหมายนั้นได้


ดังนั้นข้อมูลที่กลับมาดูเหมือนจะเป็นBufferวัตถุซึ่งฉันไม่คุ้นเคย ในทางทฤษฎีฉันสามารถใช้new Buffer(data.Body).toString('utf-8');เพื่อเข้าถึงเนื้อหาได้หรือไม่?
Sara Tibbetts

4
หากเนื้อหาเป็น Buffer อยู่แล้วไม่จำเป็นต้องสร้าง Buffer ใหม่จากสิ่งนั้น data.Body.toString('utf-8');เพียงแค่ทำ บัฟเฟอร์คือการแสดงข้อมูลไบนารีในโหนดหากคุณต้องการข้อมูลเพิ่มเติมนี่คือเอกสาร
peteb

4
สิ่งนี้ใช้ได้กับข้อความ แต่มีวิธีแก้ปัญหาทั่วไปสำหรับจัดการไฟล์ข้อความเช่นเดียวกับ. png, .jpg ฯลฯ หรือไม่
carter

4
@carter นี่เป็นวิธีแก้ปัญหาทั่วไป เพียงแค่เปลี่ยน.toString('utf8')เมื่อมีการเข้าถึงdata.Bodyไป.toString('binary')ถ้าคุณต้องการสตริงไบนารีสำหรับภาพ หากBufferin data.Bodyไม่จำเป็นต้องถูกแปลงเป็น String เหมือนในคำถามนี้คุณก็สามารถกลับมาdata.Bodyและใช้งานBufferได้โดยตรง
peteb

1
"แปลง Body จาก Buffer เป็น String" ... จะดีมากถ้าเอกสาร AWS ทำให้เรื่องนี้ชัดเจนขึ้นอีกนิด ฉันเริ่มเบื่อกับการต่อสู้กับ AWS
osullic

30

อ้างอิงจากคำตอบของ @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()`
getObject('my-bucket', 'path/to/the/object.txt').then(...);

5
.promise () ที่ท้าย getObject () เป็นกุญแจสำคัญสำหรับฉัน ฉันพบว่า AWS SDK ไม่ได้ใช้งานง่ายในบางครั้ง
Andrew Harris

คำตอบของฉันบอกว่า 'Promise {<pending>}'
jonask

1
@jonask getObject()เป็นฟังก์ชั่น async คุณลองเรียกมันด้วยawait getObject(...)ไหม
Arian Acosta

6

สำหรับคนที่กำลังมองหา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);
        }
    }

4

หรือคุณสามารถใช้ไลบรารีไคลเอ็นต์ 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)
  })
})

Disclaimer: ผมทำงานMinioเปิดแหล่งที่มาของมัน S3 เก็บรักษาวัตถุที่เข้ากันได้เขียนใน golang กับห้องสมุดของลูกค้าที่มีอยู่ในJava , Python , Js , golang


พยายาม mino แต่จะรับข้อมูลบัฟเฟอร์ได้อย่างไรเมื่อฉันพิมพ์ dataStream ร่างกายของมันให้ 'ไม่ได้กำหนด' เช่น console.log ('datastream', dataStream.Body); // undefined
Dibish

3

เมื่อมองแวบแรกดูเหมือนว่าคุณทำอะไรผิด แต่คุณไม่ได้แสดงรหัสทั้งหมดของคุณ สิ่งต่อไปนี้ใช้ได้ผลสำหรับฉันเมื่อฉันตรวจสอบ S3 และโหนดเป็นครั้งแรก:

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());
        });
    }
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.