Express开发中S3上传返回的Location数据为什么无法push到数组?
你遇到的是典型的JavaScript异步执行顺序问题。s3.upload是异步回调方法,回调内的push逻辑会在文件上传到S3成功后才触发,而你写的console.log(imageUrls)是同步代码,会在所有上传回调执行前就运行,所以此时数组还未被填充,不是push操作没有生效,是你读取数组的时机早于数据写入的时机。
修复方案
将回调形式的S3操作转为Promise形式,配合async/await等待所有上传任务完成后再读取数组、操作数据库、返回响应,修复后代码如下:
exports.imageUpload = async function (req, res) { try { // 入参校验 if (!req.files || !req.params.listingId) return res .status(400) .json({ success: false, msg: 'No files given OR no listing ID given' }); const listing = await Listing.find({ _id: req.params.listingId }).limit(1); if (!listing || listing.length < 1) return res .status(400) .json({ success: false, msg: 'Listing does not exist' }); // 初始化S3实例 const s3 = new AWS.S3({ accessKeyId: process.env.awsaccessKey, secretAccessKey: process.env.awssecretKey, Bucket: bucketname, }); // 等待桶创建完成(如果桶已经提前创建可删除这行逻辑) await s3.createBucket().promise(); const files = req.files; // 收集所有上传任务的Promise const uploadPromises = files.map((file) => { const params = { Bucket: 'kret-static/listingImages', // 建议Key加时间戳/随机前缀,避免同名文件覆盖 Key: `${Date.now()}_${file.originalname}`, Body: file.buffer, ACL: 'public-read', }; return s3.upload(params).promise(); }); // 等待所有上传任务完成 const uploadResults = await Promise.all(uploadPromises); // 提取所有图片地址,此时数组已经完全填充 const imageUrls = uploadResults.map(item => item.Location); console.log(imageUrls); // 保存地址到数据库 listing[0].images = imageUrls; // 替换为你自己的Listing模型图片字段名 await listing[0].save(); return res.json({ success: true, imageUrls }); } catch (err) { console.log(err); return res.status(500).json({ success: false, error: err.message }); } };
注意事项
- 如果S3桶已经提前创建完成,可删除
s3.createBucket相关逻辑,减少接口不必要的耗时 - 给上传文件的Key添加时间戳/随机字符串前缀,可避免不同用户上传同名文件被覆盖的问题
内容的提问来源于stack exchange,提问作者Stinny
相关产品推荐
相关产品推荐

