web-dev-qa-db-fra.com

Méthode de téléchargement Javascript AWS SDK S3 avec flux de corps générant un fichier vide

J'essaie d'utiliser la méthode upload from s3 using a ReadableStream depuis le module fs.

Le documentation indique qu'un ReadableStream peut être utilisé dans Bodyparam:

Body Buffer, Typed Array, Blob, String, ReadableStream) Object data.

De plus, la description de la méthode de téléchargement est:

Télécharge un tampon, un objet blob ou un flux de taille arbitraire, en utilisant une gestion simultanée intelligente des pièces si la charge utile est suffisamment importante.

Aussi, ici: --- (Téléchargez le pdf généré sur AWS S3 en utilisant nodejs aws sdk le @shivendra dit qu'il peut utiliser un ReadableStream et cela fonctionne.

Voici mon code:

const fs = require('fs')
const S3 = require('aws-sdk/clients/s3')

const s3 = new S3()

const send = async () => {
  const rs = fs.createReadStream('/home/osman/Downloads/input.txt')
  rs.on('open', () => {
    console.log('OPEN')
  })
  rs.on('end', () => {
    console.log('END')
  })
  rs.on('close', () => {
    console.log('CLOSE')
  })
  rs.on('data', (chunk) => {
    console.log('DATA: ', chunk)
  })

  console.log('START UPLOAD')

  const response = await s3.upload({
    Bucket: 'test-bucket',
    Key: 'output.txt',
    Body: rs,
  }).promise()

  console.log('response:')
  console.log(response)
}

send().catch(err => { console.log(err) })

Il obtient cette sortie:

START UPLOAD
OPEN
DATA: <Buffer 73 6f 6d 65 74 68 69 6e 67>
END
CLOSE
response:
{ ETag: '"d41d8cd98f00b204e9800998ecf8427e"',
  Location: 'https://test-bucket.s3.amazonaws.com/output.txt',
  key: 'output.txt',
  Key: 'output.txt',
  Bucket: 'test-bucket' }

Le problème est que mon fichier généré à S3 (output.txt) a 0 octets.

Quelqu'un sait ce que je fais mal?

Si je passe un tampon sur Body ça marche.

Body: Buffer.alloc(8 * 1024 * 1024, 'something'), 

Mais ce n'est pas ce que je veux faire. Je voudrais le faire en utilisant un flux pour générer un fichier et diriger un flux vers S3 tant que je le génère.

10
osmanpontes

Il s'agit d'un problème d'interface API utilisant NodeJS ReadableStreams. Il suffit de commenter le code lié à l'événement d'écoute 'data', Résout le problème.

const fs = require('fs')
const S3 = require('aws-sdk/clients/s3')

const s3 = new S3()

const send = async () => {
  const rs = fs.createReadStream('/home/osman/Downloads/input.txt')
  rs.on('open', () => {
    console.log('OPEN')
  })
  rs.on('end', () => {
    console.log('END')
  })
  rs.on('close', () => {
    console.log('CLOSE')
  })
  // rs.on('data', (chunk) => {
  //   console.log('DATA: ', chunk)
  // })

  console.log('START UPLOAD')

  const response = await s3.upload({
    Bucket: 'test-bucket',
    Key: 'output.txt',
    Body: rs,
  }).promise()

  console.log('response:')
  console.log(response)
}

send().catch(err => { console.log(err) })

Bien que ce soit une API étrange, lorsque nous écoutons l'événement 'data', Le ReadableStream démarre le mode fluide (écouter un événement qui change d'état de l'éditeur/EventEmitter? Oui, très sujettes aux erreurs ...). Pour une raison quelconque, le S3 a besoin d'un en pauseReadableStream. Si nous mettons rs.on('data'...) après await s3.upload(...) cela fonctionne. Si nous mettons rs.pause() après rs.on('data'...) et avant await s3.upload(...), ça marche aussi.

Maintenant, que se passe-t-il? Je ne sais pas encore ...

Mais le problème a été résolu, même s'il n'est pas complètement expliqué.

18
osmanpontes
  1. Vérifiez si le fichier /home/osman/Downloads/input.txt existe et est accessible par le processus node.js
  2. Pensez à utiliser la méthode putObject

Exemple:

const fs = require('fs');
const S3 = require('aws-sdk/clients/s3');

const s3 = new S3();

s3.putObject({
  Bucket: 'test-bucket',
  Key: 'output.txt',
  Body: fs.createReadStream('/home/osman/Downloads/input.txt'),
}, (err, response) => {
  if (err) {
    throw err;
  }
  console.log('response:')
  console.log(response)
});

Je ne sais pas comment cela fonctionnera avec async .. await, mieux vaut que le téléchargement vers AWS: S3 fonctionne d'abord, puis modifiez le flux.


MISE À JOUR: Essayez d'implémenter le téléchargement directement via ManagedUpload

const fs = require('fs');
const S3 = require('aws-sdk/clients/s3');

const s3 = new S3();

const upload = new S3.ManagedUpload({
  service: s3,
  params: {
    Bucket: 'test-bucket',
    Key: 'output.txt',
    Body: fs.createReadStream('/home/osman/Downloads/input.txt')
  }
});

upload.send((err, response) => {
  if (err) {
    throw err;
  }
  console.log('response:')
  console.log(response)
});
1
dr.dimitru