[Golang] Dùng Lambda Để Lưu và Lấy Image Từ AWS S3
Mục Tiêu
- Lưu ảnh lên Amazon Simple Storage Service
- Lấy ảnh từ Amazon Simple Storage Service, giới hạn TTL
Chuẩn Bị
- Bạn có đọc thêm series để nắm căn bản: https://viblo.asia/s/golang-lambda-serverless-vElaB8eD5kw
API Lưu Image
- Image được input dưới dạng base64
Cấu Hình ENV
Trong file serverless.yaml, add 2 env
provider:
environment:
S3_BUCKET: "images-dev-serverlessdeploymentbucket-1g3trol0zorpp"
IMAGE_BLOG: "image-blog/"
- Sau khi deploy thành công, thì truy cập aws-console search S3 service để check bucket của project => copy và bỏ vào env
- Env
IMAGE_BLOG
là image sẽ được lưu sub-folder trong bucket
List function Code
Tạo AWS session
func CreateSession(req AwsReq) *session.Session {
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
return sess
}
- Để có thể tạo được session, yêu cầu cấu hình credential trước. Checkout Cấu Hình AWS Credential để cấu hình credential
Func kiểm tra size của image
// fn upload image to s3, request iamge is base64
func CheckSizeBase64(baseImage *string) error {
sizeByte := base64.StdEncoding.DecodedLen(len(*baseImage))
sizeRe := 5000000
if sizeByte > sizeRe {
err := fmt.Errorf("size image large, require size %d and size input %d", sizeRe, sizeByte)
return err
}
return nil
}
- Image từ client dưới dạng base64 => check size bằng cách kiểm tra số lượng kí tự của base64
- Func check số lượng kí tự vượt quá 5 triệu thì sẽ báo lỗi
Func Lưu image đến s3
func StoreS3(ctx context.Context, reqDTO StoreS3Req) (*s3.PutObjectOutput, StoreS3Reponse, error) {
var (
dataRes = StoreS3Reponse{}
err error
putOut = &s3.PutObjectOutput{}
)
if reqDTO.BaseImage == nil {
return putOut, dataRes, fmt.Errorf("base64 of image is require")
}
if len(*reqDTO.BaseImage) == 0 {
return putOut, dataRes, fmt.Errorf("byte image decode empty")
}
splitBase := strings.Split(*reqDTO.BaseImage, "base64,")
var newBase string
if len(splitBase) > 1 {
newBase = splitBase[1]
} else {
newBase = splitBase[0]
}
byteImage, err := base64.StdEncoding.DecodeString(newBase)
if err != nil {
fmt.Println("image decode string err", err)
return putOut, dataRes, err
}
mimeType := http.DetectContentType(byteImage)
fmt.Println("mime type:", mimeType)
if !strings.Contains(mimeType, "jpeg") && !strings.Contains(mimeType, "png") {
return putOut, dataRes, fmt.Errorf("mime type error")
}
byteReader := bytes.NewReader(byteImage)
dataRes.PathImage = reqDTO.PathImage
session := CreateSession(AwsReq{
CustomEndpoint: reqDTO.CustomEndpoint,
})
putOut, err = s3.New(session).PutObject(&s3.PutObjectInput{
Body: byteReader,
Bucket: aws.String(GetS3Bucket()),
Key: aws.String(dataRes.PathImage),
ContentType: &mimeType,
})
return putOut, dataRes, err
}
- Line code
mimeType := http.DetectContentType(byteImage)
kiểm tra type của image, chỉ handle 2 dạng type ['png','jpeg']
Một số func phụ khác:
- Get bucket name từ environment:
func GetS3Bucket() string {
bucket := os.Getenv("S3_BUCKET")
if bucket != "" {
return bucket
}
log.Default().Println("GetS3Bucket default value:", "pkg.BucketDefault")
return "pkg.BucketDefault"
}
=> lấy bucket-name thừ environment, nếu env rỗng thì sử dụng bucket-name mặc định.
Test API
- Request data:
{
"requestId":"",
"requestTime":"",
"data": {
"file_name": "ducnp",
"name":"ducnp5-test1",
"phone":"0335288888",
"partner_id":"myst",
"user_id":"ducnp",
"image":"****am6firEVHTsD//2Q==****"
}
}
- Response data:. Truy cập S3 thì sẽ thấy ảnh đã lưu thành công.
ERROR
- Có thể xuất hiện lỗi này: ==> truy cập vào cloud-watch, để check error. Thường là do chưa cấp quyền cho Role access vào S3.
API Get Image
- Tương tự như lưu ảnh, API get image thì chỉ khác 1 chỗ đó là hàm
PresignUrl
List function Code
PresignUrl
func PresignUrl(reqAws AwsReq, presign PresignUrlReq) (string, error) {
var (
url string
err error
)
clientS3 := CreateS3Client(reqAws)
req, _ := clientS3.GetObjectRequest(&s3.GetObjectInput{
Bucket: aws.String(presign.Bucket),
Key: aws.String(presign.KeyPath),
})
url, err = req.Presign(presign.UrlTtl)
if err != nil {
return url, fmt.Errorf("presign url err %s", err)
}
return url, err
}
- Trong func có thuộc tính
TTL
là giới hạn thời gian access đến image.
Test API
- Request:
{
"requestId":"",
"requestTime":"",
"data": {
"pathImage": "image-blog/0335288888landucnp5-test1"
}
}
- Response:
{
"data": {
"url": "https://images-dev-serverle****blog/0335288888landucnp5-test1?X-Amz-***mz-Credential=ASIAQ52H7T***"
},
"responseCode": "00",
"responseId": "8b2f9168-4ad4-4f6c-b0b6-8b78f3d7c99d",
"responseMessage": "successfully",
"responseTime": "2023-02-05T01:28:17Z"
}
==> copy url và mở bằng browser để xem.
- Image hết hạn:
Contact
- facebook: https://www.facebook.com/phucducdev/
- gmail: ducnp09081998@gmail.com or phucducktpm@gmail.com
- linkedin: https://www.linkedin.com/in/phucducktpm/
- hashnode: https://hashnode.com/@OpenDev
- telegram: https://t.me/OpenDevGolang
All rights reserved