Serverless+Lambda部署Express代码,S3图片URL显示损坏问题求助
问题描述
我是AWS和Serverless框架新手。相同的Express.js代码,在Elastic Beanstalk单独部署后端时,能正常上传图片到AWS S3,生成的URL可以在浏览器正常显示图片;但用Serverless框架通过Lambda函数部署后,虽然能把图片上传到同一个S3存储桶,生成的图片URL却只显示损坏图标(图片无法打开的默认占位图)。两种场景下,上传后获取的图片URL都会和其他文本数据一起存储到Amazon RDS MySQL数据库里。我已经确认Access Key和Secret Key是正确的,相关配置代码如下:
serverless.yaml 文件
service: serverlessbackend frameworkVersion: "3" provider: name: aws runtime: nodejs18.x region: ap-south-1 timeout: 10 environment: DB_HOST: "something.rds.amazonaws.com" DB_USER: "user" DB_PASSWORD: "something" DB_NAME: "something" AWS_ACCESSKEY: "something" AWS_SECRETKEY: "something" MY_AWS_REGION: "ap-south-1" functions: myLambdaFunction: handler: index.handler events: - http: ANY / - http: "ANY {proxy+}" plugins: - serverless-offline
index.js 文件
const serverless = require("serverless-http"); const express = require("express"); const app = express(); const mysql = require("mysql2"); app.use(express.json()); let pool = require("./db/index"); let categoryRoutes = require("./routes/categoryRoutes"); app.use("/category", categoryRoutes); module.exports.handler = serverless(app);
categoryRoutes.js 文件
const express = require("express"); const { pool } = require("../db"); const { deleteFromAws, uploadToAws } = require("../utils/aws"); const multer = require("multer"); const { uniqueString } = require("../utils/unique"); const router = express.Router(); const storage = multer.memoryStorage(); const upload = multer({ storage: storage, }); router.post("/", upload.single("image"), async (req, res) => { console.log(req.file); if (!req.file) { return res.status(400).json({ error: "No file uploaded" }); } try { let result = await uploadToAws(req.file); let { Location: imgUrl, Key } = result; console.log(result); if (imgUrl && Key) { const query = "INSERT INTO temp SET ?"; const data = { category: req.body.category, category_id: uniqueString(), image_path: imgUrl, image_name: Key, }; // The "?" in the query is a placeholder for the data object pool.query(query, data, (err, result) => { if (err) { console.log(err); return res.status(400).json({ message: err.message }); } // console.log(result); return res.status(200).json({ message: "File uploaded successfully" }); }); } else { throw new Error("something wrong"); } } catch (err) { console.log(err.message); res.send(err.message); } });
uploadToAws 工具文件
const AWS = require("aws-sdk"); const { generateUniqueImageName } = require("./unique"); // Configure AWS credentials AWS.config.update({ accessKeyId: process.env.AWS_ACCESSKEY, secretAccessKey: process.env.AWS_SECRETKEY, region: process.env.MY_AWS_REGION, // e.g., 'us-east-1' }); // Create a new instance of the S3 service const uploadToAws = async (file) => { // console.log(file); const s3 = new AWS.S3(); const params = { Bucket: "something", Key: `uploads/IMG-${generateUniqueImageName(file.originalname)}`, // The file name to be used in the S3 bucket ContentType: file.mimetype, Body: file.buffer, // The file content as a buffer }; return await s3.upload(params).promise(); };
Serverless框架部署后的图片URL显示效果

Elastic Beanstalk部署后的图片URL显示效果

排查与解决方向
检查文件内容完整性
- 在Lambda环境中打印
req.file.buffer的大小,对比Elastic Beanstalk环境中的值,确认文件是否完整传递。Lambda默认请求payload上限为6MB,若图片超过该大小会被截断,导致S3中文件损坏。
- 在Lambda环境中打印
验证S3对象实际内容
- 直接在AWS控制台下载Lambda上传的图片,查看本地是否能打开。如果本地也无法打开,说明上传过程中文件内容已损坏。
检查Lambda执行角色权限
- 虽然使用了硬编码密钥,但Lambda环境更推荐用IAM角色。确认Lambda执行角色是否具备
s3:PutObject权限,且无额外限制导致上传异常。
- 虽然使用了硬编码密钥,但Lambda环境更推荐用IAM角色。确认Lambda执行角色是否具备
核实ContentType设置
- 确认Lambda环境中
file.mimetype是否正确获取,比如是否被错误识别为application/octet-stream。可手动根据文件后缀指定ContentType,或在S3控制台查看已上传文件的ContentType是否匹配图片类型。
- 确认Lambda环境中
查看Lambda日志
- 检查CloudWatch中的Lambda日志,确认
uploadToAws函数是否报错,或result返回的Location、Key等信息是否异常。
- 检查CloudWatch中的Lambda日志,确认
内容的提问来源于stack exchange,提问作者Ankit Devbanshi
相关产品推荐
相关产品推荐

