Bagaimana cara mendapatkan respons dari S3 getObject di Node.js?

90

Dalam proyek Node.js saya mencoba mendapatkan kembali data dari S3.

Saat saya menggunakan getSignedURL, semuanya bekerja:

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

Parameter saya adalah:

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

Jika saya mengambil output URL ke konsol dan menempelkannya di browser web, itu mengunduh file yang saya butuhkan.

Namun, jika saya mencoba menggunakan getObjectsaya mendapatkan segala macam perilaku aneh. Saya yakin saya hanya menggunakannya secara tidak benar. Inilah yang saya coba:

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

Keluaran:

{ 
  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

Jadi tampaknya ini berfungsi dengan baik. Namun, ketika saya meletakkan breakpoint pada salah satu console.logs, IDE saya (NetBeans) membuat kesalahan dan menolak untuk menunjukkan nilai data. Meskipun ini mungkin saja IDE, saya memutuskan untuk mencoba cara lain untuk menggunakannya getObject.

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

Ini tidak menghasilkan apa pun. Menempatkan breakpoint di menunjukkan bahwa kode tidak pernah mencapai salah satu dari console.logs. Saya juga mencoba:

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

Namun, ini juga tidak menampilkan apa pun dan menempatkan breakpoint menunjukkan bahwa console.logtidak pernah tercapai.

Apa yang saya lakukan salah?

Sara Tibbetts
sumber
Apakah awsobjek Anda sebenarnya adalah objek baru aws.S3? Selain itu, apakah tanggapan getObject()akan dikirimkan kembali ke tanggapan http atau sedang disalurkan ke file?
peteb
@b aws = new AWS.S3(). Respons tidak boleh disalurkan ke file. Saya perlu menggunakannya di Javascript
Sara Tibbetts
Jadi apakah aman untuk mengasumsikan bahwa isinya adalah JSON atau XML?
peteb
@peteb juga tidak, mereka adalah format file kustom
Sara Tibbetts
Tunjukkan parameter yang Anda gunakan dalam getObject()panggilan. Jika Anda mencoba meneruskan URL yang ditandatangani ke getObject, saya rasa itu tidak akan berhasil.
Tandai B

Jawaban:

177

Saat melakukan getObject()dari S3 API, sesuai dokumen , konten file Anda berada di Bodyproperti, yang dapat Anda lihat dari output sampel Anda. Anda harus memiliki kode yang terlihat seperti berikut ini

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

Anda mungkin tidak perlu membuat buffer baru dari data.Bodyobjek, tetapi jika perlu, Anda dapat menggunakan contoh di atas untuk melakukannya.

peteb
sumber
Jadi data yang kembali sepertinya adalah Bufferobjek, yang tidak saya kenal. Secara teoritis saya dapat menggunakan new Buffer(data.Body).toString('utf-8');untuk mendapatkan konten?
Sara Tibbetts
4
Jika konten sudah menjadi Buffer, tidak perlu membuat Buffer baru dari situ. Lakukan saja data.Body.toString('utf-8');. Buffer adalah representasi dari data biner dalam node, jika Anda membutuhkan info lebih lanjut di sini adalah docs
peteb
4
Ini berfungsi untuk teks, tetapi apakah ada solusi umum untuk menangani file teks serta .png, .jpg, dll.?
carter
4
@carter Ini adalah solusi umum. Ubah saja .toString('utf8')saat mengakses data.Bodyke .toString('binary')jika Anda menginginkan string biner untuk gambar. Jika Bufferin data.Bodytidak perlu diubah menjadi String seperti dalam pertanyaan ini, Anda dapat kembali data.Bodydan bekerja dengan Bufferlangsung.
peteb
1
"Ubah Tubuh dari Buffer ke String" ... akan sangat bagus jika dokumen AWS membuatnya sedikit lebih jelas. Saya mulai muak bergulat dengan AWS.
osullic
30

Berdasarkan jawaban @peteb, tapi menggunakan Promisesdan 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(...);
Arian Acosta
sumber
5
.Promise () di akhir getObject () adalah kuncinya bagi saya. Saya merasa AWS SDK terkadang tidak intuitif.
Andrew Harris
Tanggapan saya mengatakan 'Janji {<pending>}'
jonask
1
@jonask getObject()adalah fungsi asinkron, apakah Anda mencoba memanggilnya dengan await getObject(...)?
Arian Acosta
6

Untuk seseorang yang mencari NEST JS TYPESCRIPTversi di atas:

    /**
     * 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);
        }
    }
Chaos Legion
sumber
4

Alternatifnya, Anda bisa menggunakan perpustakaan klien 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)
  })
})

Penafian: Saya bekerja untuk Minio Sumber terbuka, penyimpanan objek kompatibel S3 yang ditulis dalam golang dengan pustaka klien tersedia di Java , Python , Js , golang .

koolhead17
sumber
Mencoba mino, tetapi bagaimana cara mendapatkan data buffer, ketika saya mencetak dataStream.Body-nya memberikan 'tidak ditentukan'. yaitu console.log ('datastream', dataStream.Body); // undefined
Dibish
3

Pada pandangan pertama, sepertinya Anda tidak melakukan kesalahan tetapi Anda tidak menampilkan semua kode Anda. Yang berikut ini berhasil bagi saya ketika saya pertama kali memeriksa S3 dan 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());
        });
    }
});
ksatria
sumber