对象自定义元数据--使用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请求。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容