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: <bucket>, Key: <key> ):
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():如何捕获错误?