En un proyecto de Node.js, estoy intentando recuperar datos de S3.
Cuando lo uso getSignedURL
, todo funciona:
aws.getSignedUrl('getObject', params, function(err, url){
console.log(url);
});
Mis params son:
var params = {
Bucket: "test-aws-imagery",
Key: "TILES/Level4/A3_B3_C2/A5_B67_C59_Tiles.par"
Si llevo la salida de la URL a la consola y la pego en un navegador web, descarga el archivo que necesito.
Sin embargo, si trato de usarlo getObject
, obtengo todo tipo de comportamiento extraño. Creo que lo estoy usando incorrectamente. Esto es lo que he probado:
aws.getObject(params, function(err, data){
console.log(data);
console.log(err);
});
Salidas:
{
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
Entonces parece que esto está funcionando correctamente. Sin embargo, cuando pongo un punto de interrupción en uno de los console.log
s, mi IDE (NetBeans) arroja un error y se niega a mostrar el valor de los datos. Si bien este podría ser solo el IDE, decidí probar otras formas de uso getObject
.
aws.getObject(params).on('httpData', function(chunk){
console.log(chunk);
}).on('httpDone', function(data){
console.log(data);
});
Esto no genera nada. Poner un punto de interrupción muestra que el código nunca llega a ninguno de los console.log
s. También probé:
aws.getObject(params).on('success', function(data){
console.log(data);
});
Sin embargo, esto tampoco genera nada y colocar un punto de interrupción muestra que console.log
nunca se alcanza.
¿Qué estoy haciendo mal?
fuente
aws
objeto realmente una nueva instancia delaws.S3
objeto? Además, ¿la respuestagetObject()
se devuelve a una respuesta http o se envía a un archivo?aws = new AWS.S3()
. La respuesta no debe enviarse a un archivo. Necesito usarlo en JavascriptgetObject()
llamada. Si está intentando pasar una URL firmada a getObject, no creo que funcione.Respuestas:
Al hacer una
getObject()
desde la API de S3, según los documentos, el contenido de su archivo se encuentra en laBody
propiedad, que puede ver en su salida de muestra. Debería tener un código que se parezca a lo siguienteconst 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 });
Es posible que no necesite crear un nuevo búfer a partir del
data.Body
objeto, pero si lo necesita, puede usar el ejemplo anterior para lograrlo.fuente
Buffer
objeto con el que no estoy familiarizado. ¿Teóricamente podría utilizarnew Buffer(data.Body).toString('utf-8');
para llegar al contenido?data.Body.toString('utf-8');
. Un búfer es una representación de datos binarios en el nodo, si necesita más información aquí están los documentos.toString('utf8')
al accederdata.Body
a.toString('binary')
si desea una cadena binaria para las imágenes. Si elBuffer
dedata.Body
no necesita ser convertido a una cadena como en esta pregunta, a continuación, puedes regresardata.Body
y trabajar con elBuffer
directamente.Basado en la respuesta de @peteb, pero usando
Promises
yAsync/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(...);
fuente
getObject()
es una función asíncrona, ¿intentaste llamarla conawait getObject(...)
?Para alguien que busque una
NEST JS TYPESCRIPT
versión de lo anterior:/** * 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); } }
fuente
Alternativamente, puede usar la biblioteca cliente 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) }) })
Descargo de responsabilidad: trabajo para Minio Su almacenamiento de objetos de código abierto compatible con S3 escrito en golang con bibliotecas cliente disponibles en Java , Python , Js , golang .
fuente
A primera vista, no parece que esté haciendo nada mal, pero no muestra todo su código. Lo siguiente funcionó para mí cuando revisé por primera vez S3 y 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()); }); } });
fuente