Node.js中无法从AWS S3管道传输对象的问题求助
问题排查与解决方案
问题根源
你的代码存在两个核心问题:
getMedia函数同时混用了await和回调函数,AWS SDK的getObject在传入回调时不会返回Promise,导致await拿到的不是有效的响应对象,后续调用createReadStream或访问data.Body自然会出错。- 回调函数内的
throw err无法被外层try/catch捕获,因为回调是异步执行的,错误会被吞掉或触发未捕获异常。
修正方案
方案一:通过Promise获取完整响应对象,再使用Body流
修改getMedia函数,移除回调,使用Promise版本获取响应:
async getMedia(key) { const params = { Bucket: process.env.AWS_BUCKET_NAME, Key: key, }; // 注意:AWS SDK v2 需要调用 .promise() 转为Promise;v3 直接 await s3.getObject(params) 即可 const data = await s3.getObject(params).promise(); return data; }
对应路由代码修改为:
router.get('/:path/:key', async (req, res, next) => { try { const key = req.params.key; const path = req.params.path; const data = await fileService.getMedia(`${path}/${key}`); data.Body.pipe(res); // Body是可读流,直接管道到响应 } catch (error) { next(error); } });
方案二:直接返回可读流(更高效,无需等待文件全量下载)
如果不需要完整响应对象,可直接返回S3的可读流,省去中间等待步骤:
// 无需async,直接返回流对象 getMedia(key) { const params = { Bucket: process.env.AWS_BUCKET_NAME, Key: key, }; return s3.getObject(params).createReadStream(); }
对应路由代码(需监听流的错误):
router.get('/:path/:key', (req, res, next) => { try { const key = req.params.key; const path = req.params.path; const stream = fileService.getMedia(`${path}/${key}`); stream.pipe(res); // 监听流错误,传递给Express错误处理中间件 stream.on('error', next); } catch (error) { next(error); } });
注意事项
- 确认AWS SDK版本:v2需调用
.promise(),v3的getObject本身返回Promise,且流获取方式略有差异(需使用GetObjectCommand配合send方法)。 - 流的错误必须监听,否则出现错误时会导致请求挂起,方案二中已通过
stream.on('error', next)处理。
内容的提问来源于stack exchange,提问作者datsenkoboos
相关产品推荐
相关产品推荐

