You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 16:23:15