Meteor+React上传AWS S3问题:upload_parts无法传递至后端
问题诊断与修复方案
看起来你遇到了异步调用顺序错误+后端参数缺失的双重问题,导致upload_parts无法正确传递到后端,让我们一步步解决:
核心问题分析
1. 异步调用顺序逻辑错误
你在uploadIt方法里的循环中使用了异步的Meteor.call('aws.uploadPart'),但JavaScript不会等待这些异步调用完成就直接执行后续的aws.completeUpload调用。这时候所有分块上传还没返回结果,upload_parts数组完全是空的,后端自然接收不到任何数据。
2. 后端uploadPart方法缺少关键参数
在server/methods.js的aws.uploadPart方法里,你给S3的请求参数没有包含Body: blob——这意味着你根本没把文件分块内容传给S3,API调用会直接失败,连ETag都拿不到,upload_parts自然无法被填充。
修复步骤
第一步:修复后端uploadPart方法
在server端的方法中添加Body参数,把文件分块内容传给S3:
'aws.uploadPart' (filename, blob, upload_id, index) { let params = { Bucket: s3_bucket, Key: filename, PartNumber: index, UploadId: upload_id, Body: blob // 新增这一行,传入文件分块内容 } return new Promise((resolve, reject) => { s3.uploadPart(params, (err, data) => { if (err) reject(err) if (data) resolve(data) }) }) },
第二步:修复客户端异步调用逻辑
使用Promise.all等待所有分块上传完成后,再调用completeUpload。把uploadIt方法改成异步函数:
uploadIt = async (e) => { e.preventDefault(); const t = e.target const upload_id = this.state.uploadId const media_file = t.media_file.files[0] console.log(`mediafile: ${media_file}`) try { const FILE_CHUNK_SIZE = 10000000 // 10MB const fileSize = media_file.size const filename = media_file.name const NUM_CHUNKS = Math.round(fileSize / FILE_CHUNK_SIZE) + 1 // 收集所有分块上传的Promise const uploadPromises = []; for (let index = 1; index < NUM_CHUNKS + 1; index++) { const start = (index - 1)*FILE_CHUNK_SIZE const end = (index)*FILE_CHUNK_SIZE const blob = (index < NUM_CHUNKS) ? media_file.slice(start, end) : media_file.slice(start) // 把每个Meteor.call包装成Promise const uploadPromise = new Promise((resolve, reject) => { Meteor.call('aws.uploadPart', filename, blob, upload_id, index, (err, res) => { if (err) { console.log("uploading part error ", err) reject(err); } if (res) { resolve({Etag: res.ETag, PartNumber: index}); } }) }); uploadPromises.push(uploadPromise); } // 等待所有分块上传完成,拿到完整的upload_parts const upload_parts = await Promise.all(uploadPromises); console.log("upload_parts: ", upload_parts) // 现在调用completeUpload,确保参数已正确填充 Meteor.call('aws.completeUpload', filename, upload_id, upload_parts, (err, res) => { console.log("Complete upload called *****") if (err) console.log("Complete upload err: ", err) if (res) console.log("Complete upload res: ", res) }) } catch(err) { console.log(err) } }
额外优化建议
- 可以添加上传进度的状态更新,实时反馈给用户;
- 增加分块上传失败的重试逻辑,避免单个分块失败导致整个上传功亏一篑;
- 不要在代码中硬编码AWS密钥,改用Meteor环境变量(比如
process.env.AWS_ACCESS_KEY_ID)配置,提升安全性。
内容的提问来源于stack exchange,提问作者chidimo
相关产品推荐
相关产品推荐

