web-dev-qa-db-fra.com

s3.getObject (). createReadStream (): Comment intercepter l'erreur?

J'essaye d'écrire un programme pour obtenir un fichier Zip de s3, le décompresser, puis le télécharger sur S3 . Mais j'ai trouvé deux exceptions que je ne peux pas attraper.

1.StreamContentLengthMismatch: Stream content length mismatch. Received 980323883 of 5770104761 bytes. Cela se produit de manière irrégulière.

2.NoSuchKey: The specified key does not exist. Cela se produit lorsque je saisis la mauvaise clé.

Lorsque ces deux exceptions se produisent, ce programme se bloque.

Je voudrais attraper et gérer ces deux exceptions correctement.

Je veux éviter un crash.

   const unzipUpload = () => {
        return new Promise((resolve, reject) => {
            let rStream = s3.getObject({Bucket: 'bucket', Key: 'hoge/hoge.Zip'})
                .createReadStream()
                    .pipe(unzip.Parse())
                    .on('entry', function (entry) {
                        if(entry.path.match(/__MACOSX/) == null){

                            // pause
                            if(currentFileCount - uploadedFileCount > 10) rStream.pause()

                            currentFileCount += 1
                            var fileName = entry.path;
                            let up = entry.pipe(uploadFromStream(s3,fileName))

                            up.on('uploaded', e => {
                                uploadedFileCount += 1
                                console.log(currentFileCount, uploadedFileCount)

                                //resume
                                if(currentFileCount - uploadedFileCount <= 10) rStream.resume()

                                if(uploadedFileCount === allFileCount) resolve()
                                entry.autodrain()
                            }).on('error', e => {
                                reject()
                            })
                        }

                    }).on('error', e => {
                        console.log("unzip error")
                        reject()
                    }).on('finish', e => {
                        allFileCount = currentFileCount
                    })
            rStream.on('error', e=> {
                console.log(e)
                reject(e)
            })
        })
    }

    function uploadFromStream(s3,fileName) {
        var pass = new stream.PassThrough();

        var params = {Bucket: "bucket", Key: "hoge/unzip/" + fileName, Body: pass};
        let request = s3.upload(params, function(err, data) {
            if(err) pass.emit('error')
            if(!err) pass.emit('uploaded')
        })
        request.on('httpUploadProgress', progress => {
            console.log(progress)
        })

        return pass
    }

C’est la bibliothèque que j’utilise pour décompresser . https://github.com/mhr3/unzip-stream

Aidez moi!!

15
tomoya ishizaka

Si vous souhaitez intercepter l'erreur NoSuchKey renvoyée par createReadStream, vous avez 2 options:

  1. Vérifiez si la clé existe avant de la lire.
  2. Erreur de capture du flux

Premier :

s3.getObjectMetadata(key)
  .promise()
  .then(() => {
    // This will not throw error anymore
    s3.getObject().createReadStream();
  })
  .catch(error => {
    if (error.statusCode === 404) {
      // Catching NoSuchKey
    }
  });

Le seul cas où vous ne rencontrerez pas d'erreur si le fichier était supprimé en une fraction de seconde, entre l'analyse de la réponse de getObjectMetadata et l'exécution de createReadStream

Seconde

s3.getObject().createReadStream().on('error', error => {
    // Catching NoSuchKey & StreamContentLengthMismatch
});

Cette approche est plus générique et interceptera toutes les autres erreurs, telles que les problèmes de réseau.

13
Vlad Holubiev

Vous devez écouter l'erreur émise plus tôt. Votre gestionnaire d'erreurs recherche uniquement les erreurs pendant la décompression.

Une version simplifiée de votre script.

s3.getObject(params)
.createReadStream()
.on('error', (e) => {
  // handle aws s3 error from createReadStream
})
.pipe(unzip)
.on('data', (data) => {
  // retrieve data
})
.on('end', () => {
  // stream has ended
})
.on('error', (e) => {
  // handle error from unzip
});

De cette manière, vous n'avez pas besoin d'appeler AWS pour savoir s'il existe ou non.

2
dmo

Vous pouvez écouter les événements (tels que erreur, données, fin) du flux que vous recevez. En savoir plus sur les événements

function getObjectStream (filePath) {
  return s3.getObject({
    Bucket: bucket,
    Key: filePath
  }).createReadStream()
}

let readStream = getObjectStream('/path/to/file.Zip')
readStream.on('error', function (error) {
  // Handle your error here.
})

Testé pour l'erreur "No Key".

it('should not be able to get stream of unavailable object', function (done) {
  let filePath = 'file_not_available.Zip'

  let readStream = s3.getObjectStream(filePath)
  readStream.on('error', function (error) {
    expect(error instanceof Error).to.equal(true)
    expect(error.message).to.equal('The specified key does not exist.')
    done()
  })
})

Testé pour le succès.

it('should be able to get stream of available object', function (done) {
  let filePath = 'test.Zip'
  let receivedBytes = 0

  let readStream = s3.getObjectStream(filePath)
  readStream.on('error', function (error) {
    expect(error).to.equal(undefined)
  })
  readStream.on('data', function (data) {
    receivedBytes += data.length
  })
  readStream.on('finish', function () {
    expect(receivedBytes).to.equal(3774)
    done()
  })
})
1
Rash