Как получить ответ от S3 getObject в Node.js?

В проекте 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. Я также пробовал:

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

Однако это также ничего не выводит, и установка точки останова показывает, что console.log никогда не достигается.

Что я делаю неправильно?


person Sara Tibbetts    schedule 29.04.2016    source источник
comment
Действительно ли ваш aws объект является новым экземпляром объекта aws.S3? Кроме того, передается ли ответ от getObject() обратно на HTTP-ответ или он передается в файл?   -  person peteb    schedule 29.04.2016
comment
@peteb aws = new AWS.S3(). Ответ не должен передаваться в файл. Мне нужно использовать его в Javascript   -  person Sara Tibbetts    schedule 29.04.2016
comment
Итак, можно ли предположить, что содержимое - это JSON или XML?   -  person peteb    schedule 29.04.2016
comment
@peteb тоже, это пользовательский формат файла   -  person Sara Tibbetts    schedule 29.04.2016
comment
Покажите параметры, которые вы используете в вызове getObject(). Если вы пытаетесь передать подписанный URL-адрес в getObject, я не думаю, что это сработает.   -  person Mark B    schedule 29.04.2016
comment
@peteb отредактировал, чтобы показать параметры   -  person Sara Tibbetts    schedule 29.04.2016


Ответы (8)


При выполнении getObject() из S3 API, согласно docs содержимое вашего файла находится в свойстве 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, но при необходимости вы можете использовать приведенный выше пример для этого.

person peteb    schedule 29.04.2016
comment
Таким образом, возвращаемые данные кажутся Buffer объектом, с которым я не знаком. Теоретически я мог бы использовать new Buffer(data.Body).toString('utf-8'); для доступа к контенту? - person Sara Tibbetts; 29.04.2016
comment
Если содержимое уже является буфером, создавать из него новый буфер не нужно. Просто сделайте data.Body.toString('utf-8');. Буфер - это представление двоичных данных в узле. Если вам нужна дополнительная информация, вот документы - person peteb; 29.04.2016
comment
Спасибо! Это было бы намного проще, если бы я действительно мог заставить работать точку останова. По какой-то причине (и это единственное место, где это произошло) внутри функции Netbeans отказывается отображать какие-либо значения переменных - person Sara Tibbetts; 29.04.2016
comment
Это работает для текста, но есть ли общее решение для работы с текстовыми файлами, а также с .png, .jpg и т. Д.? - person carter; 24.02.2018
comment
@carter Это общее решение. Просто измените .toString('utf8') при доступе к data.Body на .toString('binary'), если вам нужна двоичная строка для изображений. Если Buffer в data.Body не нужно преобразовывать в String, как в этом вопросе, вы можете просто вернуть data.Body и работать с Buffer напрямую. - person peteb; 24.02.2018
comment
Преобразовать тело из буфера в строку ... было бы здорово, если бы в документации AWS это было немного более понятно. Мне уже надоело бороться с AWS. - person osullic; 23.06.2020

На основе ответа @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(...);
person Arian Acosta    schedule 24.10.2018
comment
.Promise () в конце getObject () был для меня ключевым. Иногда мне кажется, что AWS SDK немного не интуитивно понятен. - person Andrew Harris; 29.10.2018
comment
Мой ответ гласит "Обещаю {‹pending›}". - person jonask; 09.12.2018
comment
@jonask getObject() - это асинхронная функция, вы пробовали вызывать ее с помощью await getObject(...)? - person Arian Acosta; 10.12.2018

Для тех, кто ищет 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);
        }
    }
person Chaos Legion    schedule 07.10.2019

В качестве альтернативы вы можете использовать клиентскую библиотеку 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)
  })
})

Отказ от ответственности: я работаю в Minio, это хранилище объектов с открытым исходным кодом, совместимое с S3, написанное на golang с клиентскими библиотеками, доступными в Java, Python, Js, golang.

person koolhead17    schedule 01.05.2016
comment
Пробовал mino, но как получить данные буфера, когда я печатаю dataStream.Body, он дает undefined. т.е. console.log («поток данных», dataStream.Body); //неопределенный - person Dibish; 07.03.2019

На первый взгляд не похоже, что вы делаете что-то не так, но вы не показываете весь свой код. Когда я впервые проверял 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());
        });
    }
});
person bknights    schedule 29.04.2016

Чрезвычайно похожий ответ на @ArianAcosta выше. За исключением того, что я использую import (для Node 12.x и выше), добавляю конфигурацию AWS и сниффинг для полезной нагрузки изображения и применяю обработку base64 к 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}`)
  }
}
person serraosays    schedule 04.06.2021

Предположим, что мой объект S3 выглядит так, как показано ниже:  введите описание изображения здесь

Теперь я хочу получить доступ к файлу ElasticsearchConfigNew.json из корзины. Перед доступом к S3 у вас должно быть разрешение. Определите политику и прикрепите ее к роли.

введите описание изображения здесь

Код Nodejs

let AWS = require('aws-sdk');
let s3 = new AWS.S3();
 exports.handler = async (event) => {
  await getFromS3().then((message) => {
console.log("After success", message);
}).catch((message) => {
console.log("After Failure",message);
});
};



async function getFromS3 (){
await new Promise((resolve, reject) => {

        console.log(" Accessing to S3 ");
        
        let lambda_params = {
            Bucket: 'px-library', //S3 Bucket Name
            Key:   "ElasticsearchConfigNew.json" //File present inside S3 Bucket
            };

    // Call S3 to obtain a list of the objects in the bucket
    s3.getObject(lambda_params, function(err, data) {
      if (err) {
        console.log("Error", err);
        reject(err);
      } else {
        console.log("Success  : ",data.Body.toString());
        resolve(data.Body.toString());
      }
    });
  });
  }
person Ajay Kharat    schedule 12.04.2021

Это версия 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);
person loretoparisi    schedule 27.04.2021