对象自定义元数据--使用AWS SDK接口添加

之前文章用go http API实现了给ceph对象添加和修改自定义元数据。后面思考是否还有其他路径。

专门查看了aws-sdk-go中的接口(代码路径service/s3/api.go)。其中S3客户端API中提供了一个CopyObject接口,和之前文章s3cmd的addHeader功能Go实现 中描述使用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.

说明该接口可以用来添加定制化的信息。于是,验证一下这个接口完成添加自定义元数据的任务。

1、前提

  • 安装Ceph RGW服务;
  • 安装aws-sdk-go。

2、 aws-sdk-go提供的接口

以下接口信息均在 service/s3/api.go中。

2.1 拷贝对象接口 CopyObject

接收输入结构体CopyObjectInput,输出CopyObjectOutput结构体和error错误。流程也很简单:
1、调用CopyObjectRequest函数创建一个请求。
2、使用aws/request.Request的Send()方法发送到指定服务,将返回结果写到out中。

func (c *S3) CopyObject(input *CopyObjectInput) (*CopyObjectOutput, error) {
        req, out := c.CopyObjectRequest(input)
        return out, req.Send()
}

2.2 创建拷贝对象请求接口 CopyObjectRequest

创建一个request.Request请求。设置request.Operation的结构体,包含请求的方法、路径、参数和返回等。

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 输入结构体 CopyObjectInput

设置拷贝对象输入参数的结构体。这个结构体比较长,截取了比较重要的几个属性。

  • Bucket 目的桶名称
  • CopySource 源对象的具体路径
  • Key 目的对象的名称
  • Metadata Metadata是一个哈希结构,存储键值对。在写添加Key-Value的时候会自动给Key添加x-amz-meta-的前缀。
  • MetadataDirective 值为COPY或REPLACE。表示元数据是完全拷贝还是替换方式设置。
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封装了对应结构体的方法,如设置元数据的方法SetMetadata。

// SetMetadata sets the Metadata field's value.
func (s *CopyObjectInput) SetMetadata(v map[string]*string) *CopyObjectInput {
        s.Metadata = v
        return s
}

设置元数据复制参数的SetMetadataDirective。

// SetMetadataDirective sets the MetadataDirective field's value.
func (s *CopyObjectInput) SetMetadataDirective(v string) *CopyObjectInput {
        s.MetadataDirective = &v
        return s
}

对应输出结构体CopyObjectOutput,暂时可以不用不做介绍。

3、测试用例代码

流程简单:
1、创建会话;
2、设置请求;
3、调用接口发送请求。

3.1 创建会话

s3客户端的创建需要传递一个会话结构体Session。会话的存放了配置信息和处理句柄。

type Session struct {
        Config   *aws.Config
        Handlers request.Handlers
        options Options
}

会话结构体的初始化,需要使用aws.config 结构体(默认会去~/.aws/config读取相应的配置初始化),具体结构体可查看aws/config.go文件中的定义。

aws.config 设置参数,如访问点Endpoint、区域、认证信息等。其中S3ForcePathStyle参数在本实验中设置成True

S3ForcePathStyle *bool 

该参数要求请求以 http://s3.amazonaws.com/BUCKET/KEY 形式发送(目前测试环境用的Ceph是这种方式)。默认S3客户端使用的形式是http://BUCKET.s3.amazonaws.com/KEY。如果不设置请求会找不到请求去向而报错。

3.2 创建请求

创建CopyObjectInput请求,并设置自定义元数据和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 发送请求

调用S3 客户端API的CopyObject方法发送请求。

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())
}

结果

自定义标签展示。

数据标签.png

写在最后

  • 仔细研读aws的go sdk,相比较http API接口,aws提供的接口屏蔽了一些操作,更High Level一些,让代码更清晰。
  • aws的接口代码提供了比较实用的注释,理解起来容易。
  • 直接使用REPLACE方式会导致元数据的丢失,最标准的方式(和文章s3cmd的addHeader功能Go实现 类似):
    1、通过HEAD请求获得头部信息;
    2、将结果HeadObjectOutput复制到CopyObjectInput结构中,并做自定义元数据的增加或修改;
    3、发送CopyObject请求。

你可能感兴趣的:(对象自定义元数据--使用AWS SDK接口添加)