使用Lambda与Node.js向S3传图:本地正常Serverless部署后图片损坏
问题分析与解决
核心问题原因
在AWS Serverless(Lambda)环境中,使用multer.diskStorage将文件写入/tmp目录后立即读取上传,可能因Lambda临时存储的特性导致文件未完全写入就被读取,引发文件内容截断;另外硬编码ContentType为image/jpeg,若上传其他格式图片会导致S3识别错误,也会表现为图片损坏。
解决方案
1. 将multer存储方式改为内存存储
替换diskStorage为memoryStorage,直接在内存中处理文件,规避Lambda临时磁盘的IO问题:
import multer from "multer"; import crypto from "crypto"; export default { storage: multer.memoryStorage(), // 改用内存存储 filename(request, file, callback) { const fileHash = crypto.randomBytes(10).toString("hex"); const filename = `${fileHash}-${file.originalname}`; // 添加哈希避免文件名重复覆盖 return callback(null, filename); }, };
2. 修改S3上传逻辑,使用内存Buffer上传
memoryStorage生成的文件对象包含buffer属性,直接用该Buffer作为S3请求的Body,无需读取文件流:
class S3Storage { private client: S3Client; constructor() { this.client = new S3Client({ region: "us-east-1", }); } async saveFile(file: any): Promise<void> { const fileName = `public/user-profiles/${file.filename}`; const uploadParams = { Bucket: BUCKET_NAME, Key: fileName, ACL: "public-read", Body: file.buffer, // 使用内存中的文件Buffer ContentType: file.mimetype, // 沿用文件实际的MIME类型,避免硬编码 }; await this.client.send(new PutObjectCommand(uploadParams)); } }
3. 修正路由中的文件处理逻辑
确保路由正确传递文件对象(memoryStorage与diskStorage的文件对象结构multer已做统一处理):
import uploadConfig from "../config/upload"; const routes = Router(); const upload = multer(uploadConfig); routes.post("/upload", upload.single("image"), async (request, response) => { const { file } = request; const uploadImagesService = new UploadImagesService(); await uploadImagesService.execute(file); return response.json({ success: true }); }); export default routes;
额外注意事项
- Lambda内存配置:上传大图片时需确保Lambda内存配置足够,避免内存溢出;
- 文件大小限制:可在multer配置中添加
limits: { fileSize: 5 * 1024 * 1024 }限制单文件最大为5MB; - 权限验证:确认Lambda执行角色拥有S3 PutObject权限,且Bucket的ACL配置正确。
内容的提问来源于stack exchange,提问作者Felipe Santiago
相关产品推荐
相关产品推荐

