Làm cách nào để nhận phản hồi từ S3 getObject trong Node.js?


89

Trong một dự án Node.js, tôi đang cố gắng lấy lại dữ liệu từ S3.

Khi tôi sử dụng getSignedURL, mọi thứ hoạt động:

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

Các thông số của tôi là:

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

Nếu tôi lấy đầu ra URL đến bảng điều khiển và dán nó vào trình duyệt web, nó sẽ tải xuống tệp tôi cần.

Tuy nhiên, nếu tôi cố gắng sử dụng, getObjecttôi nhận được đủ loại hành vi kỳ quặc. Tôi tin rằng tôi chỉ đang sử dụng nó không đúng cách. Đây là những gì tôi đã thử:

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

Kết quả đầu ra:

{ 
  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

Vì vậy, có vẻ như điều này đang hoạt động bình thường. Tuy nhiên, khi tôi đặt một điểm ngắt vào một trong các console.logs, IDE (NetBeans) của tôi gặp lỗi và từ chối hiển thị giá trị của dữ liệu. Trong khi đây chỉ có thể là IDE, tôi quyết định thử các cách khác để sử dụng getObject.

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

Điều này không tạo ra bất cứ điều gì. Đưa một điểm ngắt vào cho thấy rằng mã không bao giờ đạt đến một trong hai điểm console.log. Tôi cũng đã thử:

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

Tuy nhiên, điều này cũng không xuất ra bất cứ thứ gì và việc đặt một điểm ngắt cho thấy rằng console.logkhông bao giờ đạt được.

Tôi đang làm gì sai?


awsĐối tượng của bạn có thực sự là một phiên bản mới của aws.S3đối tượng không? Ngoài ra, phản hồi từ getObject()được chuyển trở lại phản hồi http hay nó đang được chuyển đến một tệp?
peteb

@peteb aws = new AWS.S3(). Phản hồi không được chuyển đến một tệp. Tôi cần phải sử dụng nó trong Javascript
Sara Tibbetts

Vì vậy, có an toàn khi giả định rằng nội dung là JSON hoặc XML không?
peteb

@peteb không, họ là một định dạng file tùy chỉnh
Sara Tibbetts

Hiển thị các thông số bạn đang sử dụng trong getObject()cuộc gọi. Nếu bạn đang cố gắng chuyển một URL đã ký vào getObject, tôi không nghĩ điều đó sẽ hiệu quả.
Mark B

Câu trả lời:


173

Khi thực hiện một getObject()từ API S3, theo tài liệu , nội dung tệp của bạn nằm trong thuộc Bodytính mà bạn có thể thấy từ đầu ra mẫu của mình. Bạn sẽ có mã trông giống như sau

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
});

Bạn có thể không cần tạo bộ đệm mới từ data.Bodyđối tượng nhưng nếu cần, bạn có thể sử dụng mẫu ở trên để đạt được điều đó.


Vì vậy, dữ liệu quay trở lại dường như là một Bufferđối tượng mà tôi không quen thuộc. Về mặt lý thuyết, tôi có thể sử dụng new Buffer(data.Body).toString('utf-8');để truy cập nội dung?
Sara Tibbetts

4
Nếu nội dung đã là Bộ đệm, không cần tạo Bộ đệm mới từ đó. Đơn giản chỉ cần làm data.Body.toString('utf-8');. Một Buffer là một đại diện của Binary dữ liệu trong nút, nếu bạn cần thêm thông tin ở đây là các tài liệu
peteb

4
Điều này hoạt động đối với văn bản, nhưng có giải pháp chung nào để xử lý các tệp văn bản cũng như .png, .jpg, v.v. không?
carter

4
@carter Đây là một giải pháp chung. Chỉ cần thay đổi .toString('utf8')khi truy cập data.Bodythành .toString('binary')nếu bạn muốn một chuỗi nhị phân cho hình ảnh. Nếu Bufferin data.Bodykhông cần phải được chuyển đổi thành Chuỗi như trong câu hỏi này, thì bạn có thể quay lại data.Bodyvà làm việc Buffertrực tiếp với.
peteb

1
"Chuyển đổi Nội dung từ Bộ đệm thành Chuỗi" ... sẽ rất tuyệt nếu tài liệu AWS làm rõ điều này hơn một chút. Tôi khá chán khi đánh vật với AWS.
osullic

29

Dựa trên câu trả lời của @peteb, nhưng sử dụng PromisesAsync/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
Đối với tôi, .promise () ở cuối getObject () là chìa khóa. Đôi khi tôi thấy AWS SDK hơi không trực quan.
Andrew Harris

Câu trả lời của tôi là 'Promise {<
pend

1
@jonask getObject()là một hàm không đồng bộ, bạn đã thử gọi nó bằng await getObject(...)chưa?
Arian Acosta

6

Đối với ai đó đang tìm kiếm một NEST JS TYPESCRIPTphiên bản của điều trên:

    /**
     * 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

Ngoài ra, bạn có thể sử dụng thư viện máy khách 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)
  })
})

Tuyên bố từ chối trách nhiệm: Tôi làm việc cho Minio Nguồn mở của nó, lưu trữ đối tượng tương thích S3 được viết bằng golang với các thư viện khách có sẵn bằng Java , Python , Js , golang .


Đã thử nhỏ, nhưng làm thế nào để lấy dữ liệu bộ đệm, khi tôi in dataStream.Body của nó cho "không xác định". tức là console.log ('datastream', dataStream.Body); // undefined
Dibish

3

Thoạt nhìn có vẻ như bạn không làm gì sai nhưng bạn không hiển thị tất cả mã của mình. Những điều sau đây phù hợp với tôi khi tôi lần đầu tiên kiểm tra S3 và 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());
        });
    }
});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.