如何让Node.js等待pdf.on('end')中S3文件上传完成?
解决S3上传完成前返回元数据导致的文件访问404问题
你的问题核心在于:pdf.on('end')的异步回调并没有被当前流程等待,pdf.end()执行后直接就生成签名URL并返回了元数据,这时候S3的上传操作还在后台运行,自然会出现文件未上传完成就访问导致的404,日志顺序也印证了这点——Finished with pdf:先输出,之后才是S3 Upload Success。
要让整个流程等待S3上传完成,最可靠的方式是把end事件的处理逻辑包装成Promise,用await等待它执行完毕,再进行后续的签名URL生成和返回操作。修改后的代码如下:
// 将pdf的end事件和S3上传包装成Promise await new Promise(async (resolve) => { pdf.on('end', async () => { const result = Buffer.concat(chunks); await s3.putObject({ Bucket: 'corp-attch', Key: filePath, Body: result, ContentType: 'application/pdf', }).promise(); this.logger.log(`S3 Upload Success: ${filePath}`); resolve(); // 上传完成后resolve这个Promise }); await pdf.end(); }); this.logger.log(`Finished with pdf: ${filePath}`); returnAttach.attachDest = filePath; returnAttach.attachName = filePath.split('/').pop(); const getObjectParams = { Bucket: this.configService.awsCorpBucketName, Key: filePath, Expires: 900, }; returnAttach.attachUrl = s3.getSignedUrl('getObject', getObjectParams); return returnAttach;
关键改动说明
- 把原来的
pdf.on('end')和pdf.end()逻辑放进一个新的Promise里,只有当S3上传完成并调用resolve()后,这个Promise才会完成 - 用
await等待这个Promise,确保后续生成签名URL、返回元数据的操作,都在S3上传完成之后执行 - 最后直接返回
returnAttach即可,不需要额外包装一层Promise(当前函数应为async函数,直接返回值会自动被包装成Promise)
这样修改后,日志顺序会变成先输出S3 Upload Success,再输出Finished with pdf:,生成的签名URL访问时文件已经存在于S3,就不会出现404了。
内容的提问来源于stack exchange,提问作者RenControl
相关产品推荐
相关产品推荐

