Golang Lambda将图片上传至S3静态网站方案问询
解决方案:Golang Lambda 处理表单文件并上传至S3 Images文件夹
核心步骤概述
- 解析API Gateway传入的表单数据(含文件)
- 将临时文件写入Lambda的
/tmp目录 - 对图片进行缩放处理
- 重命名处理后的文件
- 上传至S3存储桶的
images文件夹(通过指定对象前缀实现)
完整代码示例
package main import ( "io" "mime/multipart" "os" "path/filepath" "strings" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3" "github.com/disintegration/imaging" ) const ( s3BucketName = "your-static-site-bucket" // 替换为你的存储桶名称 maxWidth = 800 // 缩放后的最大宽度 maxHeight = 600 // 缩放后的最大高度 ) func handler(req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { // 1. 解析multipart表单数据 boundary := strings.Split(req.Headers["Content-Type"], "boundary=")[1] reader := multipart.NewReader(strings.NewReader(req.Body), boundary) form, err := reader.ReadForm(10 << 20) // 限制表单最大为10MB if err != nil { return events.APIGatewayProxyResponse{StatusCode: 400, Body: "表单解析失败"}, err } defer form.RemoveAll() // 2. 获取上传的图片文件(假设表单字段名为"image") fileHeaders := form.File["image"] if len(fileHeaders) == 0 { return events.APIGatewayProxyResponse{StatusCode: 400, Body: "未上传图片文件"}, nil } fileHeader := fileHeaders[0] srcFile, err := fileHeader.Open() if err != nil { return events.APIGatewayProxyResponse{StatusCode: 500, Body: "打开上传文件失败"}, err } defer srcFile.Close() // 3. 将文件写入Lambda的/tmp目录 tmpSrcPath := filepath.Join("/tmp", fileHeader.Filename) dstFile, err := os.Create(tmpSrcPath) if err != nil { return events.APIGatewayProxyResponse{StatusCode: 500, Body: "创建临时文件失败"}, err } defer dstFile.Close() defer os.Remove(tmpSrcPath) // 执行完成后清理临时文件 _, err = io.Copy(dstFile, srcFile) if err != nil { return events.APIGatewayProxyResponse{StatusCode: 500, Body: "保存临时文件失败"}, err } // 4. 图片缩放处理 srcImg, err := imaging.Open(tmpSrcPath) if err != nil { return events.APIGatewayProxyResponse{StatusCode: 500, Body: "读取图片失败"}, err } // 按比例缩放,不超过设定的最大宽高 resizedImg := imaging.Fit(srcImg, maxWidth, maxHeight, imaging.Lanczos) // 5. 将缩放后的图片写入/tmp目录(添加重命名前缀) resizedFileName := "resized_" + fileHeader.Filename tmpResizedPath := filepath.Join("/tmp", resizedFileName) resizedFile, err := os.Create(tmpResizedPath) if err != nil { return events.APIGatewayProxyResponse{StatusCode: 500, Body: "创建缩放后文件失败"}, err } defer resizedFile.Close() defer os.Remove(tmpResizedPath) // 执行完成后清理临时文件 err = imaging.Encode(resizedFile, resizedImg, imaging.JPEG, imaging.JPEGQuality(80)) if err != nil { return events.APIGatewayProxyResponse{StatusCode: 500, Body: "编码缩放图片失败"}, err } // 6. 上传至S3的images文件夹 sess, err := session.NewSession(&aws.Config{ Region: aws.String("us-east-1"), // 替换为你的存储桶所在区域 }) if err != nil { return events.APIGatewayProxyResponse{StatusCode: 500, Body: "创建AWS会话失败"}, err } s3Client := s3.New(sess) uploadFile, err := os.Open(tmpResizedPath) if err != nil { return events.APIGatewayProxyResponse{StatusCode: 500, Body: "打开缩放后文件失败"}, err } defer uploadFile.Close() // 关键:通过给对象Key添加"images/"前缀,实现S3"文件夹"的效果 s3Key := "images/" + resizedFileName _, err = s3Client.PutObject(&s3.PutObjectInput{ Bucket: aws.String(s3BucketName), Key: aws.String(s3Key), Body: uploadFile, ACL: aws.String("public-read"), // 静态网站需公开访问时设置此ACL }) if err != nil { return events.APIGatewayProxyResponse{StatusCode: 500, Body: "上传至S3失败"}, err } return events.APIGatewayProxyResponse{ StatusCode: 200, Body: "图片处理上传成功,访问地址: https://" + s3BucketName + ".s3.amazonaws.com/" + s3Key, }, nil } func main() { lambda.Start(handler) }
关键注意事项
- S3文件夹本质:S3没有真实的文件夹结构,
images文件夹是通过给对象Key添加images/前缀模拟实现的,上传时直接指定Key: "images/文件名"即可。 - Lambda /tmp目录限制:/tmp目录最大可用空间为512MB,处理大图片时需注意大小限制;函数执行完毕后目录会自动清理,无需手动处理残留文件。
- IAM权限配置:给Lambda执行角色添加以下策略,确保仅能上传到指定路径:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::your-static-site-bucket/images/*" } ] } - 依赖打包:部署Lambda时需编译并打包所有依赖,使用命令
GOOS=linux GOARCH=amd64 go build -o main main.go编译后,将生成的main文件打包为zip上传即可。
内容的提问来源于stack exchange,提问作者Michael Clovis
相关产品推荐
相关产品推荐

