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

Posted

技术标签:

【中文标题】s3.getObject().createReadStream() :如何捕捉错误?【英文标题】:s3.getObject().createReadStream() : How to catch the error? 【发布时间】:2017-10-03 14:22:42 【问题描述】:

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

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

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

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

我想正确地捕捉和处理这两个异常。

我想防止崩溃。

   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
    

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

帮帮我!!

【问题讨论】:

【参考方案1】:

如果您想捕捉createReadStream 引发的NoSuchKey 错误,您有两种选择:

    在读取之前检查密钥是否存在。 从流中捕获错误

第一

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

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

第二

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

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

【讨论】:

谢谢!!你的第一个想法对我来说是一个创新的想法。对于第二个想法,有些东西不起作用。 嘿,很高兴它帮助了你。我注意到您是 *** 的新手,所以如果您觉得答案可以解决您的问题 - 将其标记为“已接受”(绿色复选标记)。 您的第二个解决方案不起作用,它不会捕获 NoSuchKey 错误。我还没有找到解决这个错误的方法,所以似乎解决方案 1 是这里的唯一方法。 @dmo 感谢您的关注!我更新了我的第二个示例,因此它也可以处理错误! 我不相信 getObjectMetadata() 是 Node.js S3 SDK 上的有效方法 --- 我认为您正在寻找的是 s3.headObject( Bucket: &lt;bucket&gt;, Key: &lt;key&gt; ): docs.aws.amazon.com/AWSjavascriptSDK/latest/AWS/…【参考方案2】:

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

脚本的简化版本。

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
);

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

【讨论】:

应该工作,但由于某种原因它不起作用。来自node_modules/aws-sdk/lib/request.js:31 的错误总是逃避事件侦听器并终止进程。 我在循环中使用了类似的代码。我得到(节点:12533)MaxListenersExceededWarning:检测到可能的 EventEmitter 内存泄漏。添加了 11 个错误侦听器。使用emitter.setMaxListeners() 增加限制错误。有没有办法关闭管道? 完成后会自动关闭。如果您的循环是非阻塞的,并且您正在循环的数组中有许多项目,则您可能创建了太多的侦听器。如果非阻塞,重构它,看看你是否遇到同样的问题。如果您的循环被阻塞,请检查您的包是否可以按原样更新,这可能是依赖项中的错误。【参考方案3】:

您可以在收到的流中收听事件(如错误、数据、完成)。 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.
)

测试“无密钥”错误。

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

测试成功。

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

【讨论】:

【参考方案4】:

为防止崩溃,您需要异步侦听对象的头部元数据,它不会返回整个对象,这将花费更少的时间。试试这个!

isObjectErrorExists = async functions () => 
  try 
const s3bucket = 
secret key: '',
client id: ''

  const params = 
       Bucket: 'your bucket name',
       Key: 'path to object'
;
    await s3bucket.headObject(params).promise(); // adding promise will let you add await to listen to process untill it completes.

    return true;
   catch (err) 
      return false; // headObject threw error.
    
    throw new Error(err.message); 
  


public yourFunction = async() => 
if (await this.isObjectErrorExists()) 
s3Bucket.getObject().createReadStream(); // works smoothly


【讨论】:

虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。 @dan1st 正确,由于我们正在访问对象的元数据,因此承诺的返回持续时间较短&这个解决方案很有帮助,因为它可以用来检查对象是否会导致崩溃,它可以是轻松处理。 (反对票,因为不写描述是不对的。我的解决方案适用于最新版本的 aws-sdk 库)非常需要赞成票

以上是关于s3.getObject().createReadStream() :如何捕捉错误?的主要内容,如果未能解决你的问题,请参考以下文章

s3.getObject()。createReadStream():如何捕获错误?

获取s3对象元数据然后创建流

使用 mocha 和 chaiAsPromised 测试异步函数时的断言错误

S3 策略版本是啥意思?

S3“拒绝访问”到存储桶

S3 存储桶策略与访问控制列表