请求AWS S3不存在的对象触发Access Denied导致Node服务器崩溃如何解决
问题原因
try/catch仅能捕获同步执行阶段抛出的异常:调用s3.getObject(downloadParams).createReadStream()的同步执行阶段只要参数合法就不会抛出错误,实际的S3资源请求是流后续异步发起的,出现的Access Denied错误是通过流的error事件抛出的,没有被监听的话会成为未捕获异常,直接导致Node进程崩溃。- S3权限特性:如果你的访问身份没有配置
s3:ListBucket权限,请求不存在的对象时S3不会返回404状态,而是直接返回403 Access Denied,这是你看到该报错的业务侧原因,但该问题本身不会直接导致服务崩溃。
修复方案
首先给返回的可读流添加error事件监听,捕获异步抛出的S3请求错误即可解决崩溃问题,代码修改如下:
const getFileStream = fileName => { const downloadParams = { Key: fileName, Bucket: bucketName } return s3.getObject(downloadParams).createReadStream() } app.get('/aws-images/:id', jsonParser, (req, res) => { const id = req.params.id try { const readStream = getFileStream(id) // 监听流的错误事件,捕获异步抛出的S3请求错误 readStream.on('error', err => { // 可根据错误码自定义返回内容 if (err.statusCode === 403 || err.statusCode === 404) { res.status(404).json({msg: '请求的资源不存在'}) } else { res.status(500).json(err) } }) readStream.pipe(res) } catch (err) { // 保留原有捕获逻辑,处理同步阶段的参数错误等场景 res.status(500).json(err) } })
如果需要让不存在的对象返回标准404而不是403,可以给你的S3访问身份添加s3:ListBucket权限,配置示例如下(替换为实际桶名):
{ "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::你的桶名" }
内容的提问来源于stack exchange,提问作者Erenn
相关产品推荐
相关产品推荐

