使用aws-sdk-go上传对象到s3服务器
1.环境准备
MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。
MinIO是一个非常轻量的服务,可以很简单的和其他应用的结合,类似 NodeJS, Redis 或者 MySQL。
2.部署minio
macos推荐使用brew进行安装
1brew install minio
其他操作系统可以去minio官网上进行下载
运行
1minio server ~/Downloads # ~/Downloads为指定的工作目录
运行之后会告诉你endpoint,accesskey,secretkey信息以及相关sdk信息
使用浏览器可以进行对象存储的可视化管理
3.创建go客户端
1.新建配置文件
app.yaml
1endpoint: http://127.0.0.1:9000
2bucket: images
3accessKey: minioadmin
4secretKey: minioadmin
5pathstyle: true
2.创建对应的结构体
1var s3cfg S3cfg
2
3type S3cfg struct {
4 Endpoint string `yaml:"endpoint"`
5 Bucket string `yaml:"bucket"`
6 AccessKey string `yaml:"accesskey"`
7 SecretKey string `yaml:"secretkey"`
8 PathStyle bool `yaml:"pathstyle"`
9}
3.从配置文件读取配置
这里推荐使用viper
1 viper.AddConfigPath("./")
2 viper.SetConfigName("app")
3 viper.SetConfigType("yaml")
4 if err := viper.ReadInConfig(); err != nil {
5 log.Fatalf("read config file failed, %v", err)
6 }
7 if err := viper.Unmarshal(&s3cfg); err != nil {
8 log.Fatalf("unmarshal config file failed, %v", err)
9 }
4.创建s3客户端
建议将client单独拿出来,方便调用
1func newS3Client() *s3.S3 {
2 creds := credentials.NewStaticCredentials(s3cfg.AccessKey, s3cfg.SecretKey, "")
3 sess := session.Must(session.NewSession(&aws.Config{
4 Region: aws.String("default"),
5 Endpoint: &s3cfg.Endpoint,
6 S3ForcePathStyle: &s3cfg.PathStyle, // 因为使用的IP:Port/bucket的形式,使用path风格
7 Credentials: creds,
8 }))
9 svc := s3.New(sess)
10 return svc
11}
5.创建上传接口函数
1func uploadS3(bucket, fileName string, body []byte) error {
2 client := newS3Client()
3 _, err := client.PutObjectWithContext(context.TODO(), &s3.PutObjectInput{
4 Bucket: aws.String(bucket),
5 Key: aws.String(fileName),
6 Body: bytes.NewReader(body),
7 })
8 if err != nil {
9 if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode {
10 // If the SDK can determine the request or retry delay was canceled
11 // by a context the CanceledErrorCode error code will be returned.
12 return fmt.Errorf("upload canceled due to timeout, %v", err)
13 }
14 return fmt.Errorf("failed to upload object, %v", err)
15 }
16 return nil
17}
6.创建gin web并调用上传接口
1func main() {
2 r := gin.Default()
3
4 r.POST("/upload", upload)
5
6 r.Run(":8080")
7}
8
9func upload(ctx *gin.Context) {
10 file, err := ctx.FormFile("file")
11 if err != nil {
12 ctx.JSON(http.StatusOK, gin.H{
13 "code": 500,
14 "msg": "没有指定上传文件",
15 })
16 return
17 }
18
19 f, _ := file.Open()
20 buf := make([]byte, file.Size)
21 f.Read(buf)
22
23 // bfRd := bufio.NewReader(f)
24 // 上传对象
25 err = uploadS3(s3cfg.Bucket, file.Filename, buf)
26 if err != nil {
27 ctx.JSON(http.StatusOK, gin.H{
28 "code": "500",
29 "msg": "上传失败" + err.Error(),
30 })
31 return
32 }
33 ctx.JSON(http.StatusOK, gin.H{
34 "code": 200,
35 "msg": "文件上传成功",
36 })
37}
4.启动测试
1go run .
查看minio browser
5.附完整代码
当上传的文件比较大时可以采取分段上传,具体可以参考官方的sdkaws-sdk-go
1package main
2
3/**
4* s3上传图片
5 */
6
7import (
8 "bytes"
9 "context"
10 "fmt"
11 "log"
12 "net/http"
13
14 "github.com/aws/aws-sdk-go/aws"
15 "github.com/aws/aws-sdk-go/aws/awserr"
16 "github.com/aws/aws-sdk-go/aws/credentials"
17 "github.com/aws/aws-sdk-go/aws/request"
18 "github.com/aws/aws-sdk-go/aws/session"
19 "github.com/aws/aws-sdk-go/service/s3"
20 "github.com/gin-gonic/gin"
21 "github.com/spf13/viper"
22)
23
24var s3cfg S3cfg
25
26type S3cfg struct {
27 Endpoint string `yaml:"endpoint"`
28 Bucket string `yaml:"bucket"`
29 AccessKey string `yaml:"accesskey"`
30 SecretKey string `yaml:"secretkey"`
31 PathStyle bool `yaml:"pathstyle"`
32}
33
34func init() {
35 viper.AddConfigPath("./")
36 viper.SetConfigName("app")
37 viper.SetConfigType("yaml")
38 if err := viper.ReadInConfig(); err != nil {
39 log.Fatalf("read config file failed, %v", err)
40 }
41 if err := viper.Unmarshal(&s3cfg); err != nil {
42 log.Fatalf("unmarshal config file failed, %v", err)
43 }
44}
45
46func main() {
47 r := gin.Default()
48
49 r.POST("/upload", upload)
50
51 r.Run(":8080")
52}
53
54func upload(ctx *gin.Context) {
55 file, err := ctx.FormFile("file")
56 if err != nil {
57 ctx.JSON(http.StatusOK, gin.H{
58 "code": 500,
59 "msg": "没有指定上传文件",
60 })
61 return
62 }
63
64 f, _ := file.Open()
65 buf := make([]byte, file.Size)
66 f.Read(buf)
67
68 // bfRd := bufio.NewReader(f)
69 // 上传对象
70 err = uploadS3(s3cfg.Bucket, file.Filename, buf)
71 if err != nil {
72 ctx.JSON(http.StatusOK, gin.H{
73 "code": "500",
74 "msg": "上传失败" + err.Error(),
75 })
76 return
77 }
78 ctx.JSON(http.StatusOK, gin.H{
79 "code": 200,
80 "msg": "文件上传成功",
81 })
82}
83
84func newS3Client() *s3.S3 {
85 creds := credentials.NewStaticCredentials(s3cfg.AccessKey, s3cfg.SecretKey, "")
86 sess := session.Must(session.NewSession(&aws.Config{
87 Region: aws.String("default"),
88 Endpoint: &s3cfg.Endpoint,
89 S3ForcePathStyle: &s3cfg.PathStyle,
90 Credentials: creds,
91 }))
92 svc := s3.New(sess)
93 return svc
94}
95
96func uploadS3(bucket, fileName string, body []byte) error {
97 client := newS3Client()
98 _, err := client.PutObjectWithContext(context.TODO(), &s3.PutObjectInput{
99 Bucket: aws.String(bucket),
100 Key: aws.String(fileName),
101 Body: bytes.NewReader(body),
102 })
103 if err != nil {
104 if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode {
105 // If the SDK can determine the request or retry delay was canceled
106 // by a context the CanceledErrorCode error code will be returned.
107 return fmt.Errorf("upload canceled due to timeout, %v", err)
108 }
109 return fmt.Errorf("failed to upload object, %v", err)
110 }
111 return nil
112}
- 原文作者:黄忠德
- 原文链接:https://huangzhongde.cn/post/Golang/%E4%BD%BF%E7%94%A8aws-sdk-go%E4%B8%8A%E4%BC%A0%E5%AF%B9%E8%B1%A1%E5%88%B0s3%E6%9C%8D%E5%8A%A1%E5%99%A8/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。