前端通过AWS Lambda上传图片至S3并同步存信息到DynamoDB流程咨询
前端图片上传→AWS Lambda→S3+DynamoDB 完整实现流程
一、AWS资源配置
1. 创建S3存储桶
- 登录AWS控制台创建全局唯一命名的S3桶
- 配置CORS规则(允许前端跨域上传),在桶的「权限」→「跨域资源共享(CORS)」中添加:
[ { "AllowedHeaders": ["*"], "AllowedMethods": ["GET", "PUT"], "AllowedOrigins": ["*"], // 生产环境替换为你的前端域名 "ExposeHeaders": [] } ]
- 可选开启桶的版本控制,用于图片版本追溯
2. 创建DynamoDB表
- 新建表,主键设为
imageId(字符串类型,可使用S3对象键或UUID作为唯一标识) - 可选添加全局二级索引,方便按
uploadTime等字段查询
3. 创建IAM角色
- 新建Lambda类型的IAM角色,附加以下权限策略:
AmazonS3ReadOnlyAccess:允许Lambda读取S3对象元数据- 自定义DynamoDB策略:仅允许写入目标表(生产环境避免用全权限)
AWSLambdaBasicExecutionRole:允许Lambda写入CloudWatch日志用于调试
4. 创建Lambda函数(S3触发型)
- 选择Node.js 18.x运行时,关联上述IAM角色
- 配置S3触发器:添加S3触发源,选择目标桶,事件类型选「Put」(仅监听文件上传),可设置前缀/后缀过滤(如仅处理
.jpg/.png)
二、Lambda函数代码实现(Node.js)
功能:监听S3上传事件,提取图片元数据并写入DynamoDB
import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb"; import { marshall } from "@aws-sdk/util-dynamodb"; const dynamoDbClient = new DynamoDBClient({ region: "你的AWS区域" }); const TABLE_NAME = "你的DynamoDB表名"; export const handler = async (event) => { try { // 解析S3事件中的对象信息 const s3Record = event.Records[0].s3; const bucketName = s3Record.bucket.name; const objectKey = decodeURIComponent(s3Record.object.key.replace(/\+/g, " ")); const fileSize = s3Record.object.size; const uploadTime = new Date().toISOString(); // 构造DynamoDB写入项 const item = { imageId: objectKey, bucketName, objectKey, fileSize: fileSize.toString(), uploadTime, fileType: objectKey.split(".").pop() }; // 写入DynamoDB const command = new PutItemCommand({ TableName: TABLE_NAME, Item: marshall(item) }); await dynamoDbClient.send(command); console.log(`成功写入DynamoDB: ${objectKey}`); return { statusCode: 200, body: "处理完成" }; } catch (error) { console.error("处理失败:", error); throw error; } };
注:Lambda控制台可通过「层」或代码包包含AWS SDK v3依赖;在线编辑时可直接导入SDK(AWS已预装核心包)
三、前端上传实现(原生JS示例)
方式1:Lambda生成预签名URL(推荐,直接上传S3减少中转)
1. 新增预签名URL生成Lambda
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"; import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; const s3Client = new S3Client({ region: "你的AWS区域" }); const BUCKET_NAME = "你的S3桶名"; export const handler = async (event) => { try { const { fileName, fileType } = JSON.parse(event.body); const objectKey = `uploads/${Date.now()}_${fileName}`; // 自定义存储路径 // 生成有效期5分钟的预签名URL const command = new PutObjectCommand({ Bucket: BUCKET_NAME, Key: objectKey, ContentType: fileType }); const signedUrl = await getSignedUrl(s3Client, command, { expiresIn: 300 }); return { statusCode: 200, body: JSON.stringify({ signedUrl, objectKey }) }; } catch (error) { console.error("生成预签名URL失败:", error); return { statusCode: 500, body: "生成URL失败" }; } };
2. 配置API Gateway
- 创建REST API,添加POST方法集成上述Lambda
- 开启CORS,允许前端域名访问
3. 前端上传代码
<input type="file" id="imageUpload" accept="image/*"> <button onclick="uploadImage()">上传图片</button> <script> async function uploadImage() { const fileInput = document.getElementById('imageUpload'); const file = fileInput.files[0]; if (!file) return; try { // 1. 请求Lambda获取预签名URL const urlResponse = await fetch('你的API Gateway URL', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ fileName: file.name, fileType: file.type }) }); const { signedUrl } = await urlResponse.json(); // 2. 用预签名URL直接上传文件到S3 const uploadResponse = await fetch(signedUrl, { method: 'PUT', headers: { 'Content-Type': file.type }, body: file }); uploadResponse.ok ? alert('上传成功!') : alert('上传失败,请重试'); // 上传完成后S3自动触发Lambda写入DynamoDB } catch (error) { console.error('上传出错:', error); alert('上传出错'); } } </script>
方式2:API Gateway中转上传(不推荐,限小文件)
若不想用预签名URL,可直接将文件传给API Gateway,由Lambda接收后上传S3并写入DynamoDB,但受API Gateway默认10MB payload限制,仅适合小文件场景。
四、测试与调试
- 上传图片后检查S3桶是否存在目标文件
- 查看Lambda的CloudWatch日志,确认DynamoDB写入状态
- 验证DynamoDB表中是否存在对应图片信息
- 失败时优先排查CORS配置、IAM权限、Lambda代码逻辑
五、生产环境优化建议
- 限制S3桶CORS允许域名,避免使用
* - 最小化IAM角色权限,遵循权限最小化原则
- 前端添加文件大小、类型校验
- 配置S3生命周期规则,自动清理过期图片
- 启用DynamoDB自动扩缩容,应对高并发写入
- 为Lambda配置错误重试机制,避免数据丢失
内容的提问来源于stack exchange,提问作者fotographiya _tech
相关产品推荐
相关产品推荐

