乐趣区

干货-基于Go-SDK操作京东云对象存储OSS的入门指南

前言

本文介绍如何使用 Go 语言对京东云对象存储 OSS 进行基本的操作,帮助客户快速通过 Go SDK 接入京东云对象存储,提高应用开发的效率。

在实际操作之前,我们先看一下京东云 OSS 的 API 接口支持范围和能力。从对象存储的 API 文档可以看到,京东云提供两套接口:

1、兼容 S3 API,支持 AWS S3 接口,兼容大部分重要功能,作为后续重点开发和优化版本。由于并不是完全兼容 S3 的接口,因此需要重点阅读兼容接口列表,相关介绍见
https://docs.jdcloud.com/cn/o…

2、旧版 OSS API,京东云前期独立封装的 restful 接口,支持基本的 service、bucket、object 等操作。该版本目前仍能使用,但后续不再开发。

很明显,京东云提供兼容 S3 的接口,一方面可以快速支持原有基于 AWS S3 开发的应用程序,另一方面帮助客户的数据从 AWS S3 迁移过来。建议您使用兼容 S3 的接口,而同时京东云提供了丰富的多种语言版本的 SDK,可以根据您项目开发的需要进行不同语言 SDK 的选择。
相关介绍见
https://docs.jdcloud.com/cn/o…

这里需要注意查看兼容接口列表,对比京东云 OSS 和 AWS S3 接口的兼容情况。譬如 Put Bucket 接口仅使用通用的请求 header,默认创建权限为 private 的 bucket。由于不支持 x -amz-acl, x-amz-grant-* 等请求头,无法使用标准权限来设置 ACL(即 Canned ACL)。如果需要创建时指定 bucket ACL,需要通过另外的接口实现,这个下文会提及。
兼容接口列表:
https://docs.jdcloud.com/cn/o…

下面以 Go SDK 介绍京东云 OSS 的基本操作,实现对象资源的上传下载等功能。

环境准备

1、安装或更新 Go 1.5 及以上版本(参考 1 – Mac 下安装 Go 语言环境配置)。

2、(可选)通过可视化 IDE Atom 搭建 Go 编译环境。相比于 sublime text 或者传统的 vim 编辑方式,Atom 是更为先进的文本代码编辑器,是由 Github 打造的编程开发工具,除了界面美观,还有各种强大的插件。本文以 Atom 开发环境作为展示(参考 2 – Mac 下基于 Atom 构建 Go 开发环境)

3、在使用 Go SDK 发起请求之前,需提前在京东云用户中心账户管理下的 AccessKey 管理页面申请 accesskey 和 secretKey 密钥对(简称 AK/SK)。这个秘钥对会在后续程序初始化使用到。

下载和安装

1、命令行安装

go get github.com/aws/aws-sdk-go

2、Atom 安装(可选)
菜单【Packages】->【Go】->【Get Package】,然后输入 github.com/aws/aws-sdk-go,稍等片刻便下载和安装完成。代码会被下载到 GOPATH 环境变量中第一个路径 src 目录中,效果与命令行安装方法一样。

SDK 组成概述

在具体编码之前,建议了解 AWS SDK 的构成,主要包括 SDK core 和 service clients 两个部分。SDK core 适用于所有 AWS 的服务,service 中的 client 仅适用于对应的 service,作为该服务的客户端进行调用。

SDK core 包括一些通用的类,帮助更容易地构造 API 参数,譬如 Config、Logger 等。其中,
awserr:进程异常的接口,返回进程中遇到的异常和错误,对应错误码和信息。
credential:API 调用需要身份认证,需要使用京东云的 AK/SK 进行认证,并且需要修改默认的 Config 配置项。
endpoints:服务的调用入口,有区域属性,需要在 Config 中配置。
session:提供配置的初始化,可以自定义配置中的参数进行初始化,包括 region、endpoints、credential 等。
request:提供 API 请求和重试,可以自定义请求及其处理方法。

创建 s3 client 的示例
在发起 OSS(S3 协议)的请求之前,需要初始化 s3 client,以下为创建 client 的例子。

 1 ak := "your accesskey"
 2    sk := "your secretkey"
 3    token := "" //Token 留空
 4    creds := credentials.NewStaticCredentials(ak, sk, token)
 5    _,err := creds.Get()
 6
 7    config := &aws.Config{8        Region:      aws.String("cn-north-1"),                 //Bucket 所在 Region
 9        Endpoint:    aws.String("s3.cn-north-1.jcloudcs.com"), //Bucket 所在 Endpoint
10        DisableSSL      :aws.Bool(false),
11        Credentials     :creds,
12    }
13    client := s3.New(session.New(config))

创建完 s3 client 之后,就可以对 bucket、object 等 oss 资源进行请求操作了。下面分别介绍创建 bucket、上传文件(PutObject、Upload)、分片上传文件进行 demo 展示。

  • 创建 bucket 空间

目标:在京东云华北区创建一个名字为 go-sdk-sample 的 bucket,并设置 ACL 为公有读私有写(public-read)。
示例代码:

 1 package main
 2
 3 import (
 4    "fmt"
 5    "os"
 6    "github.com/aws/aws-sdk-go/aws"
 7    "github.com/aws/aws-sdk-go/aws/credentials"
 8    "github.com/aws/aws-sdk-go/aws/session"
 9    "github.com/aws/aws-sdk-go/service/s3"
10 )
11
12 func main() {
13    bucket := "go-sdk-sample"
14    // Create S3 service client
15    svc := s3.New(newSession())
16
17    crParams := &s3.CreateBucketInput{18        Bucket: aws.String(bucket),
19    }
20
21    _, err := svc.CreateBucket(crParams)
22
23    if err != nil {24        exitErrorf("Unable to create bucket %q, %v", bucket, err)
25    }
26
27    // Wait until bucket is created before finishing
28    fmt.Printf("Waiting for bucket %q to be created...\n", bucket)
29
30    err = svc.WaitUntilBucketExists(&s3.HeadBucketInput{31        Bucket: aws.String(bucket),
32    })
33    if err != nil {34        exitErrorf("Error occurred while waiting for bucket to be created, %v", bucket)
35    }
36
37    fmt.Printf("Bucket %q successfully created\n", bucket)
38
39    puParams := &s3.PutBucketAclInput{40        Bucket: aws.String(bucket),
41    }
42    puParams.SetACL("public-read") //set bucket ACL
43
44    _, err = svc.PutBucketAcl(puParams)
45    if err != nil {46        exitErrorf(err.Error())
47    }
48    fmt.Println("Set", bucket, "ACL to public-read")
49
50 }
51
52 func newSession() *session.Session {
53    ak := "your accesskey"
54    sk := "your secretkey"
55    token := "" //Token 留空
56
57    creds := credentials.NewStaticCredentials(ak, sk, token)
58    creds.Get()
59
60    config := &aws.Config{61        Region:      aws.String("cn-north-1"),                 //Bucket 所在 Region
62        Endpoint:    aws.String("s3.cn-north-1.jcloudcs.com"), //Bucket 所在 Endpoint
63        DisableSSL:  aws.Bool(false),
64        Credentials: creds,
65    }
66    return session.New(config)
67 }
68
69 func exitErrorf(msg string, args ...interface{}) {70    fmt.Fprintf(os.Stderr, msg+"\n", args...)
71    os.Exit(1)
72 }

示例中可以看出,我们通过 CreatBucket 的接口创建 bucket,并通过 PutBucketAcl 的接口设置 bucket 的 ACL。目前京东云支持三种访问权限,包括私有读写(private)、公有读私有写(public-read)、公有读写(public-read-write)。

执行结果:

执行成功,控制台显示对应的 bucket 创建成功。

  • 上传文件(PutObject)

目标:把一个 object 上传到 bucket 中,并加入 MD5 校验确保数据完整性。

示例代码:

 1 package main
 2
 3 import (
 4    "crypto/md5"
 5    "encoding/hex"
 6    "fmt"
 7    "io"
 8    "os"
 9
10    "github.com/aws/aws-sdk-go/aws"
11    "github.com/aws/aws-sdk-go/aws/credentials"
12    "github.com/aws/aws-sdk-go/aws/session"
13    "github.com/aws/aws-sdk-go/service/s3"
14 )
15
16 func main() {
17    filename := "your file path" //file path
18
19    file, err := os.Open(filename)
20    if err != nil {21        exitErrorf("Unable to open file %q, %v", err)
22    }
23    defer file.Close()
24
25    md5_file := CreateMd5(filename)
26
27    // Create S3 service client
28    svc := s3.New(newSession())
29
30    input := &s3.PutObjectInput{
31        Body:       file,
32        Bucket:     aws.String("go-sdk-sample"),
33        Key:        aws.String(filename),
34        ContentMD5: aws.String(md5_file), //MD5 校验(可选)35    }
36
37    result, err := svc.PutObject(input)
38
39    if err != nil {40        exitErrorf("Put Object Error, %v", err)
41    }
42
43    fmt.Println(result)
44
45 }
46 // MD5 校验
47 func CreateMd5(filename string) string {
48
49    f, err := os.Open(filename)
50    if err != nil {51        exitErrorf("Unable to open file %q, %v", err)
52    }
53    defer f.Close()
54
55    md5hash := md5.New()
56    io.Copy(md5hash, f)
57
58    return hex.EncodeToString(md5hash.Sum(nil))
59
60 }
61
62 func newSession() *session.Session {
63    ak := "your accesskey"
64    sk := "your secretkey"
65    token := "" //Token 留空
66
67    creds := credentials.NewStaticCredentials(ak, sk, token)
68    creds.Get()
69
70    config := &aws.Config{71        Region:      aws.String("cn-north-1"),                 //Bucket 所在 Region
72        Endpoint:    aws.String("s3.cn-north-1.jcloudcs.com"), //Bucket 所在 Endpoint
73        DisableSSL:  aws.Bool(false),
74        Credentials: creds,
75    }
76    return session.New(config)
77 }
78
79 func exitErrorf(msg string, args ...interface{}) {80    fmt.Fprintf(os.Stderr, msg+"\n", args...)
81    os.Exit(1)
82 }

示例中可以看出,我们通过 PutObject 接口上传本地文件,同时为了校验数据的准确性,加入了 CreateMd5 方法生成文件的 MD5 值,并传参到 ContentMD5 中,OSS 服务端会校验文件,如果为相同值会返回成功的 result,即文件的 ETAG 值。

执行结果:

可以从控制台看到文件已经正确上传,ETag 与文件计算的 MD5 值相符。可以尝试修改 ContentMD5 的参数为其他值,会返回错误结果,这里就不具体展示了。

  • 上传文件(Uploader)

上面通过 PutObject 的方法进行文件上传,那么如果文件比较大,一般通过分片上传的方式来实现分块、并发和重试机制,确保大,文件的上传。这里需要用到 CreateMultipartUpload、UploadPart、CompletedPart、AbortMultipartUpload 等多个接口来完成整个过程,同时需要自行实现重试、并行等逻辑,相对比较复杂。S3 提供了 S3 Upload Manager 来帮助用户实现以上逻辑,能够自动判断文件大小来选择单次上传或分块上传的方式来完成。同时,用户可以自定义块大小(PartSize)、并发数(Concurrency)以及最大块数量(MaxUploadParts)等参数,满足不同场景的需要。

示例代码:

 1 package main
 2
 3 import (
 4    "fmt"
 5    "os"
 6
 7    "github.com/aws/aws-sdk-go/aws"
 8    "github.com/aws/aws-sdk-go/aws/credentials"
 9    "github.com/aws/aws-sdk-go/aws/session"
10    "github.com/aws/aws-sdk-go/service/s3/s3manager"
11 )
12
13 func main() {
14    bucket := "go-sdk-sample"                                   //bucket name
15    filename := "your file path" //file url
16
17    file, err := os.Open(filename)
18    if err != nil {19        exitErrorf("Unable to open file %q, %v", err)
20    }
21    defer file.Close()
22
23    sess := newSession()
24    uploader := s3manager.NewUploader(sess)
25
26    upParams := &s3manager.UploadInput{27        Bucket: aws.String(bucket),
28        Key:    aws.String(filename),
29        Body:   file,
30    }
31
32    //
33    result, err := uploader.Upload(upParams, func(u *s3manager.Uploader) {
34        u.PartSize = 10 * 1024 * 1024  // 自定义分块大小,10M 每个分片
35        u.LeavePartsOnError = true     //true, 上传出错会保留已成功上传的分块
36        u.Concurrency = 3             // 定义并发数,即 goroutines 数量
37        u.MaxUploadParts = 10000      // 定义最大可上传块数量
38    })
39
40    if err != nil {41        exitErrorf("Put Object Error, %v", err)
42    }
43
44    fmt.Printf("Successfully uploaded!\n")
45    fmt.Println("File URL:" + result.Location)
46 }
47
48 func newSession() *session.Session {
49    ak := "your accesskey"
50    sk := "your secretkey"
51    token := "" //Token 留空
52
53    creds := credentials.NewStaticCredentials(ak, sk, token)
54    creds.Get()
55
56    config := &aws.Config{57        Region:      aws.String("cn-north-1"),                 //Bucket 所在 Region
58        Endpoint:    aws.String("s3.cn-north-1.jcloudcs.com"), //Bucket 所在 Endpoint
59        DisableSSL:  aws.Bool(false),
60        Credentials: creds,
61    }
62    return session.New(config)
63 }
64
65 func exitErrorf(msg string, args ...int,erface{}) {66    fmt.Fprintf(os.Stderr, msg+"\n", args...)
67    os.Exit(1)
68 }

可以看到,与前面 PutObject 不同,这里使用 s3manager.NewUploader 来构造上传服务,通过 uploader.Upload 方法上传文件。Upload 的具体实现逻辑可以参考源码:
https://github.com/aws/aws-sd…

譬如自动判断是否分块上传的逻辑如下:

执行结果:

本次上传的文件大小为 16M,比 PartSize 的 10M 大,因此会执行分块上传。在上传过程中,可以在控制台 - 分片管理看到对应正在上传的分片任务,说明正在分片上传。upload 的上传成功后会返回文件访问地址 location。

至此,我们已经把主要的 OSS 操作示例介绍完毕,其余的操作我们根据实际需要继续整理,譬如不使用 s3manager,直接用 MultipartUpload 等基础接口来实现分块上传,大家可以尝试一下,我们下回分解。


参考 1:Mac 下安装 Go 语言环境配置

1、安装 Go
使用 brew 进行安装,brew 是 Mac 下的一个包管理工具,类似于 CentOS 下的 yum,可以很方便地进行安装、卸载和更新各种软件包。

brew install go

安装后在终端输入 go version 查看安装的版本,我的显示 go version go1.12.5 darwin/amd64,表示安装的是 v1.12.5 版本。

2、配置环境变量
查看 go 的环境变量设置

go env

参考 2:Mac 下基于 Atom 构建 Go 开发环境

1、安装 Atom
https://atom.io/ Atom 官网,可以直接下载软件安装。

2、安装 Go 语言环境(参考 1 的步骤)

3、安装 go-plus 插件
go-plus 是 Atom 上面的一款开源的 Golang 开发环境插件,项目地址:
https://github.com/joefitzger…

在 Atom 中的 Preference 中可以找到 install 菜单,输入 go-plus。

点击:install,就会开始安装 go-plus,go-plus 插件会自动安装对应的依赖插件,如果没有安装对应的 Golang 类库可以使用 go get 安装。

安装完我们就可以进行编码,为了方便编译、测试和编译,需要配合 terminal 使用,可以通过 view-Terminal 打开终端,不需要另外切换界面。

go-plus 有非常多的特性,能够实时反馈语法错误和编译错误。每保存一个文件,go-plus 就会在后台运行你提前配置好的要执行的 go tools,例如:go vet、go oracle、go build 等等,然后将错误和警告在编辑器底部显示出来。

go-plus 同样能够在编辑器的对应行上显示该行的编译错误提示和错误信息,这样你就能很快的定位哪一行有错。大家可以尝试一下。


点击 ” 京东云 ” 了解更多详情

退出移动版