乾貨 | 基於Go SDK操作京東雲物件儲存OSS的入門指南
前言
本文介紹如何使用Go語言對京東雲物件儲存OSS進行基本的操作,幫助客戶快速通過Go SDK接入京東雲物件儲存,提高應用開發的效率。
在實際操作之前,我們先看一下京東雲OSS的API介面支援範圍和能力。從物件儲存的API文件可以看到,京東雲提供兩套介面:
1、相容S3 API,支援AWS S3介面,相容大部分重要功能,作為後續重點開發和優化版本。由於並不是完全相容S3的介面,因此需要重點閱讀相容介面列表,相關介紹見
https://docs.jdcloud.com/cn/object-storage-service/compatibility-api-overview
2、舊版OSS API,京東雲前期獨立封裝的restful介面,支援基本的service、bucket、object等操作。該版本目前仍能使用,但後續不再開發。
很明顯,京東雲提供相容S3的介面,一方面可以快速支援原有基於AWS S3開發的應用程式,另一方面幫助客戶的資料從AWS S3遷移過來。建議您使用相容S3的介面,而同時京東雲提供了豐富的多種語言版本的SDK,可以根據您專案開發的需要進行不同語言SDK的選擇。
相關介紹見
https://docs.jdcloud.com/cn/object-storage-service/introduction-3
這裡需要注意檢視相容介面列表,對比京東雲OSS和AWS S3介面的相容情況。譬如Put Bucket介面僅使用通用的請求header,預設建立許可權為private的bucket。由於不支援x-amz-acl, x-amz-grant-*等請求頭,無法使用標準許可權來設定ACL(即Canned ACL)。如果需要建立時指定bucket ACL,需要通過另外的介面實現,這個下文會提及。
相容介面列表:
https://docs.jdcloud.com/cn/object-storage-service/compatibility-api-overview
下面以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-sdk-go/blob/master/service/s3/s3manager/upload.go
譬如自動判斷是否分塊上傳的邏輯如下:
執行結果:
本次上傳的檔案大小為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/joefitzgerald/go-plus
在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同樣能夠在編輯器的對應行上顯示該行的編譯錯誤提示和錯誤資訊,這樣你就能很快的定位哪一行有錯。大家可以嘗試一下。
點選"京東雲"瞭解更多詳情