Javascript s3.getObject().createReadStream() :如何捕捉错误?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43799246/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 02:10:05  来源:igfitidea点击:

s3.getObject().createReadStream() : How to catch the error?

javascriptnode.jsamazon-web-servicesamazon-s3stream

提问by tomoya ishizaka

I am trying to write a program to get a zip file from s3, unzip it, then upload it to S3. But I found two exceptions that I can not catch.

我正在尝试编写一个程序来从 s3 获取 zip 文件,解压缩它,然后将其上传到 S3。但是我发现了两个我无法捕捉的异常。

1.StreamContentLengthMismatch: Stream content length mismatch. Received 980323883 of 5770104761 bytes.This occurs irregularly.

1.StreamContentLengthMismatch: Stream content length mismatch. Received 980323883 of 5770104761 bytes.这种情况不定期发生。

2.NoSuchKey: The specified key does not exist.This happens when I input the wrong key.

2.NoSuchKey: The specified key does not exist.当我输入错误的键时会发生这种情况。

When these two exceptions occur, this program crashes.

当这两个异常发生时,这个程序就会崩溃。

I'd like to catch and handle these two exceptions correctly.

我想正确捕获并处理这两个异常。

I want to prevent a 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
    }

This is the library I use when unzipping. https://github.com/mhr3/unzip-stream

这是我解压缩时使用的库。 https://github.com/mhr3/unzip-stream

Help me!!

帮我!!

采纳答案by Vlad Holubiev

If you'd like to catch the NoSuchKeyerror thrown by createReadStreamyou have 2 options:

如果您想捕获NoSuchKey抛出的错误,createReadStream有 2 个选项:

  1. Check if key exists before reading it.
  2. Catch error from stream
  1. 在读取之前检查密钥是否存在。
  2. 从流中捕获错误

First:

第一

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

The only case when you won't catch error if file was deleted in a split second, between parsing response from getObjectMetadataand running createReadStream

如果文件在瞬间被删除,在解析响应getObjectMetadata和运行之间,您不会捕获错误的唯一情况createReadStream

Second:

第二

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

This is a more generic approach and will catch all other errors, like network problems.

这是一种更通用的方法,可以捕获所有其他错误,例如网络问题。

回答by dmo

You need to listen for the emitted error earlier. Your error handler is only looking for errors during the unzip part.

您需要更早地侦听发出的错误。您的错误处理程序仅在解压缩部分查找错误。

A simplified version of your 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
});

This way, you do not need to make an additional call to AWS to find out if out if it exists.

这样,您无需额外调用 AWS 来确定它是否存在。

回答by Rash

You can listen to events (like error, data, finish) in the stream you are receiving back. Read more on events

您可以在收到的流中收听事件(如错误、数据、完成)。阅读更多关于活动的信息

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

Tested for "No Key" error.

测试“无钥匙”错误。

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

Tested for success.

测试成功。

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