之前文章用go http API實現(xiàn)了給ceph對象添加和修改自定義元數(shù)據(jù)。后面思考是否還有其他路徑。
專門查看了aws-sdk-go中的接口(代碼路徑service/s3/api.go)。其中S3客戶端API中提供了一個CopyObject接口,和之前文章s3cmd的addHeader功能Go實現(xiàn) 中描述使用x-amz-copy-source類似,可以完成對象的拷貝任務。特別的一點,在文檔說明中有這樣一段話:
The method is useful when you want to inject custom logic of configuration into the the SDK's request lifecycle. Such as custom headers, or retry logic.
說明該接口可以用來添加定制化的信息。于是,驗證一下這個接口完成添加自定義元數(shù)據(jù)的任務。
1、前提
- 安裝Ceph RGW服務;
- 安裝aws-sdk-go。
2、 aws-sdk-go提供的接口
以下接口信息均在 service/s3/api.go中。
2.1 拷貝對象接口 CopyObject
接收輸入結(jié)構(gòu)體CopyObjectInput,輸出CopyObjectOutput結(jié)構(gòu)體和error錯誤。流程也很簡單:
1、調(diào)用CopyObjectRequest函數(shù)創(chuàng)建一個請求。
2、使用aws/request.Request的Send()方法發(fā)送到指定服務,將返回結(jié)果寫到out中。
func (c *S3) CopyObject(input *CopyObjectInput) (*CopyObjectOutput, error) {
req, out := c.CopyObjectRequest(input)
return out, req.Send()
}
2.2 創(chuàng)建拷貝對象請求接口 CopyObjectRequest
創(chuàng)建一個request.Request請求。設置request.Operation的結(jié)構(gòu)體,包含請求的方法、路徑、參數(shù)和返回等。
func (c *S3) CopyObjectRequest(input *CopyObjectInput) (req *request.Request, output *CopyObjectOutput) {
op := &request.Operation{
Name: opCopyObject,
HTTPMethod: "PUT",
HTTPPath: "/{Bucket}/{Key+}",
}
if input == nil {
input = &CopyObjectInput{}
}
output = &CopyObjectOutput{}
req = c.newRequest(op, input, output)
return
}
2.3 輸入結(jié)構(gòu)體 CopyObjectInput
設置拷貝對象輸入?yún)?shù)的結(jié)構(gòu)體。這個結(jié)構(gòu)體比較長,截取了比較重要的幾個屬性。
- Bucket 目的桶名稱
- CopySource 源對象的具體路徑
- Key 目的對象的名稱
- Metadata Metadata是一個哈希結(jié)構(gòu),存儲鍵值對。在寫添加Key-Value的時候會自動給Key添加
x-amz-meta-的前綴。 - MetadataDirective 值為COPY或REPLACE。表示元數(shù)據(jù)是完全拷貝還是替換方式設置。
type CopyObjectInput struct {
// Bucket is a required field
Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"`
// CopySource is a required field
CopySource *string `location:"header" locationName:"x-amz-copy-source" type:"string" required:"true"`
// The key of the destination object. Key is a required field
Key *string `location:"uri" locationName:"Key" min:"1" type:"string" required:"true"`
// A map of metadata to store with the object in S3.
Metadata map[string]*string `location:"headers" locationName:"x-amz-meta-" type:"map"`
// Specifies whether the metadata is copied from the source object or replaced
// with metadata provided in the request.
MetadataDirective *string `location:"header" locationName:"x-amz-metadata-directive" type:"string" enum:"MetadataDirective"`
......
}
SDK封裝了對應結(jié)構(gòu)體的方法,如設置元數(shù)據(jù)的方法SetMetadata。
// SetMetadata sets the Metadata field's value.
func (s *CopyObjectInput) SetMetadata(v map[string]*string) *CopyObjectInput {
s.Metadata = v
return s
}
設置元數(shù)據(jù)復制參數(shù)的SetMetadataDirective。
// SetMetadataDirective sets the MetadataDirective field's value.
func (s *CopyObjectInput) SetMetadataDirective(v string) *CopyObjectInput {
s.MetadataDirective = &v
return s
}
對應輸出結(jié)構(gòu)體CopyObjectOutput,暫時可以不用不做介紹。
3、測試用例代碼
流程簡單:
1、創(chuàng)建會話;
2、設置請求;
3、調(diào)用接口發(fā)送請求。
3.1 創(chuàng)建會話
s3客戶端的創(chuàng)建需要傳遞一個會話結(jié)構(gòu)體Session。會話的存放了配置信息和處理句柄。
type Session struct {
Config *aws.Config
Handlers request.Handlers
options Options
}
會話結(jié)構(gòu)體的初始化,需要使用aws.config 結(jié)構(gòu)體(默認會去~/.aws/config讀取相應的配置初始化),具體結(jié)構(gòu)體可查看aws/config.go文件中的定義。
aws.config 設置參數(shù),如訪問點Endpoint、區(qū)域、認證信息等。其中S3ForcePathStyle參數(shù)在本實驗中設置成True。
S3ForcePathStyle *bool
該參數(shù)要求請求以 http://s3.amazonaws.com/BUCKET/KEY 形式發(fā)送(目前測試環(huán)境用的Ceph是這種方式)。默認S3客戶端使用的形式是http://BUCKET.s3.amazonaws.com/KEY。如果不設置請求會找不到請求去向而報錯。
3.2 創(chuàng)建請求
創(chuàng)建CopyObjectInput請求,并設置自定義元數(shù)據(jù)和MetadataDirective值。
input := &s3.CopyObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(destFile),
CopySource: aws.String("/cephgo/file3"),
}
cusMeta := make(map[string]*string)
city := "New York"
cusMeta["city"] = &city
input = input.SetMetadata(cusMeta)
input = input.SetMetadataDirective("REPLACE")
3.3 發(fā)送請求
調(diào)用S3 客戶端API的CopyObject方法發(fā)送請求。
ret, err := svc.CopyObject(input)
3.4 完整測試代碼
附上功能測試的代碼。
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
const (
authRegion = "default"
bucketName = "cephgo"
endPoint = "http://192.168.99.103:8080"
accessKey = "654321"
secretKey = "654321"
srcFile = "file3"
destFile = "file3"
)
func main() {
cred := credentials.NewStaticCredentials(accessKey, secretKey, "")
svc := s3.New(session.New(&aws.Config{
Region: aws.String(authRegion),
Endpoint: aws.String(endPoint),
Credentials: cred,
S3ForcePathStyle: aws.Bool(true),
}))
input := &s3.CopyObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(destFile),
CopySource: aws.String("/cephgo/file3"),
}
cusMeta := make(map[string]*string)
city := "New York"
cusMeta["city"] = &city
input = input.SetMetadata(cusMeta)
input = input.SetMetadataDirective("REPLACE")
ret, err := svc.CopyObject(input)
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(ret.String())
}
結(jié)果
自定義標簽展示。

寫在最后
- 仔細研讀aws的go sdk,相比較http API接口,aws提供的接口屏蔽了一些操作,更High Level一些,讓代碼更清晰。
- aws的接口代碼提供了比較實用的注釋,理解起來容易。
- 直接使用REPLACE方式會導致元數(shù)據(jù)的丟失,最標準的方式(和文章s3cmd的addHeader功能Go實現(xiàn) 類似):
1、通過HEAD請求獲得頭部信息;
2、將結(jié)果HeadObjectOutput復制到CopyObjectInput結(jié)構(gòu)中,并做自定義元數(shù)據(jù)的增加或修改;
3、發(fā)送CopyObject請求。