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

Javascript s3.getObject().createReadStream():如何捕获错误?,javascript,node.js,amazon-web-services,amazon-s3,stream,Javascript,Node.js,Amazon Web Services,Amazon S3,Stream,我正在尝试编写一个程序,从s3获取一个zip文件,解压缩它,然后将它上传到s3。 但我发现了两个我无法理解的例外 1.流内容长度匹配:流内容长度不匹配。收到5770104761字节中的980323883。这是不正常的 2。无按键:指定的按键不存在。当我输入错误的按键时,会发生这种情况 当这两个异常发生时,该程序崩溃 我希望捕获并正确处理这两个异常 我想防止撞车 const unzipUpload = () => { return new Promise((resolv

我正在尝试编写一个程序,从s3获取一个zip文件,解压缩它,然后将它上传到s3。 但我发现了两个我无法理解的例外

1.
流内容长度匹配:流内容长度不匹配。收到5770104761字节中的980323883。
这是不正常的

2。
无按键:指定的按键不存在。
当我输入错误的按键时,会发生这种情况

当这两个异常发生时,该程序崩溃

我希望捕获并正确处理这两个异常

我想防止撞车

   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
    }
const unzipUpload=()=>{
返回新承诺((解决、拒绝)=>{
让rStream=s3.getObject({Bucket:'Bucket',Key:'hoge/hoge.zip'})
.createReadStream()文件
.pipe(解压.Parse())
.on('entry',函数(entry){
if(entry.path.match(/\uu MACOSX/)==null){
//停顿
如果(currentFileCount-uploadedFileCount>10)rStream.pause()
currentFileCount+=1
var fileName=entry.path;
let up=entry.pipe(上传自流(s3,文件名))
up.on('Upload',e=>{
uploadedFileCount+=1
日志(currentFileCount,uploadedFileCount)
//恢复
如果(currentFileCount-uploadedFileCount{
拒绝
})
}
}).on('error',e=>{
log(“解压错误”)
拒绝
}).on('finish',e=>{
allFileCount=currentFileCount
})
rStream.on('error',e=>{
控制台日志(e)
拒绝(e)
})
})
}
函数uploadFromStream(s3,文件名){
var pass=new stream.PassThrough();
var params={Bucket:“Bucket”,Key:“hoge/unzip/”+文件名,Body:pass};
let request=s3.upload(参数、函数(错误、数据){
if(err)pass.emit('error')
如果(!err)pass.emit('uploaded')
})
on('httpUploadProgress',progress=>{
console.log(进度)
})
回程通行证
}
这是我解压缩时使用的库。


帮帮我!!

如果您想捕获
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
    });
    

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

    您可以侦听正在接收回的流中的事件(如错误、数据、完成)。

    测试“无键”错误。

    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()
      })
    })
    
    测试成功。

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

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

    脚本的简化版本

    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来确定它是否存在。

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

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

    谢谢!!你的第一个想法对我来说是一个创新的想法。对于第二个想法,有些东西不起作用。嘿,很高兴它帮助了你。我注意到你是Stackoverflow的新手,所以如果你觉得答案解决了你的问题-将其标记为“已接受”(绿色复选标记)。您的第二个解决方案不起作用,它不会捕获NoSuchKey错误。虽然我没有找到捕获此错误的方法,但似乎解决方案1是唯一的方法。@dmo感谢您的注意!我更新了第二个示例,以便它也能处理此错误!我不相信getObjectMetadata()是Node.js S3 SDK上的一个有效方法---我想你要找的是
    S3.headObject({Bucket:,Key:}):
    这应该可以工作,但由于某些原因它不能工作。
    Node\u modules/aws SDK/lib/request.js:31
    中的错误总是在逃避事件侦听器并终止进程。我在循环中使用了类似的代码。我得到了(节点:12533)MaxListenerSexceedAwarning:检测到可能的EventEmitter内存泄漏。添加了11个错误侦听器。请使用emitter.setMaxListeners()增加错误限制。是否有方法关闭管道?它将在完成后自动关闭。如果您的循环是非阻塞的,并且您正在循环的数组中有许多项,则可能创建了太多侦听器。如果是非阻塞的,请重构它并查看是否遇到相同的问题。如果您的循环是阻塞的,请检查您的packages可以更新,因为它可能是依赖性中的一个bug。虽然此代码可以回答此问题,但提供有关此代码为什么和/或如何回答此问题的其他上下文可以提高其长期价值。@dan1st正确,因为我们正在访问对象的元数据,承诺的返回持续时间较短&此解决方案尽可能提供帮助用于检查对象是否会导致崩溃,并且可以轻松处理。(不写描述的反对票是不对的。我的解决方案在最新版本的aws sdk库中运行顺利)升级票是非常需要的