- 后端
- 云原生
- 开发工具
【免费下载链接】aws-sdk-go
This SDK has reached end-of-support. The AWS SDK for Go v2 is available here: https://github.com/aws/aws-sdk-go-v2
本指南围绕仓库中的 example/service/s3/concatObjects 示例展开,讲解如何在不下载数据的前提下,通过 S3 分片上传(Multipart Upload)与
UploadPartCopy接口把两个对象按顺序拼接成一个新对象。读完本文,你将掌握CreateMultipartUpload→UploadPartCopy→CompleteMultipartUpload三段式调用链、CopySource的 URL 编码细节,以及如何把多个对象当作"分片"合成单个对象,并能在本地直接运行该示例验证效果。
一、示例背景:为什么用"对象当分片"来拼接
在 S3 中,最常见的拼接需求是"把两个已存在的对象按顺序合并成一个新对象"。常规做法是先GetObject下载两个对象到本地、再合并、最后PutObject上传,但这样既浪费带宽又耗时。本示例展示的是一条服务端路径:利用UploadPartCopy将整个对象作为一个分片(part)拷贝进一个新的分片上传任务中,两个对象对应两个分片,最终CompleteMultipartUpload把它们按分片顺序组装成一个完整对象。
整个过程数据不经过客户端,完全在 S3 服务端内部流转,这正是该方案的核心价值。示例的代码注释也明确说明了这一点:
"This is an example using the AWS SDK for Go to concatenate two objects together. We use
UploadPartCopywhich uses an object for a part. Here in this example we have two parts, or in other words two objects that we want to concatenate together."
二、示例文件与整体结构
示例只包含两个文件:
- example/service/s3/concatObjects/README.md:示例说明与运行命令;
- example/service/s3/concatObjects/concatObjects.go:完整 Go 实现。
concatObjects.go的关键结构如下(节选):
//go:build example // +build example package main import ( "log" "net/url" "os" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3" ) type client struct { s3Client *s3.S3 bucket *string }注意文件头部的//go:build example构建标签:示例程序被打上了example标签,因此直接go run concatObjects.go会被 Go 工具链忽略,必须像 README 中那样显式传入-tags example才能编译运行。
从代码结构可以推断出该示例的整体设计:用一个client结构体封装 S3 客户端与桶名,其concatenate方法负责执行两次UploadPartCopy,main函数负责参数解析、初始化客户端、发起与完成分片上传。
三、运行方式与前提条件
README 给出的运行命令为:
AWS_REGION=<region> go run -tags example concatObjects.go <bucket> <key for object 1> <key for object 2> <key for output>四个位置参数的含义:
| 参数 | 含义 |
|---|---|
<bucket> | 源对象与目标对象所在的桶名 |
<key for object 1> | 第一个源对象的 Key,将成为目标对象的第一个分片 |
<key for object 2> | 第二个源对象的 Key,将成为目标对象的第二个分片 |
<key for output> | 拼接后新对象的 Key |
运行前需要满足:
- 区域变量:通过
AWS_REGION指定 S3 所在的区域,例如AWS_REGION=us-east-1。代码内部通过session.New(&aws.Config{})创建会话,aws/session 会依次从环境变量、共享凭证文件等来源加载配置; - 凭证配置:会话依赖标准的 AWS 凭证链(环境变量、
~/.aws/credentials等),运行账号需要对两个源对象具有读取权限、对目标桶具有s3:PutObject、s3:CreateMultipartUpload等分片上传权限; - Go 环境:仓库 go.mod 声明模块为
github.com/aws/aws-sdk-go,要求 Go 1.19 及以上。
main函数对参数数量做了防御性校验(len(os.Args) < 4时打印用法并退出)。一个小细节是:代码中的错误提示写的是go run concatenateObjects.go ...,而实际文件名是concatObjects.go,以 README 与文件名为准即可。
四、核心流程:三段式分片上传拼接
第 1 步:发起分片上传(CreateMultipartUpload)
在拷贝任何分片之前,必须先让 S3 开启一个分片上传任务,获得全局唯一的UploadId:
output, err := c.s3Client.CreateMultipartUpload(&s3.CreateMultipartUploadInput{ Bucket: &bucket, Key: &key3, })对应的 API 实现位于 service/s3/api.go,CreateMultipartUploadInput结构体定义在 service/s3/api.go。该请求的HTTPMethod为POST,路径为/{Bucket}/{Key+},返回结果中携带UploadId,后续的UploadPartCopy与CompleteMultipartUpload都必须引用它。
第 2 步:用 UploadPartCopy 把对象拷贝为分片
concatenate方法按顺序发起两次UploadPartCopy,第一次对应分片 1(对象 1),第二次对应分片 2(对象 2):
foo, err := c.s3Client.UploadPartCopy(&s3.UploadPartCopyInput{ Bucket: c.bucket, CopySource: aws.String(url.QueryEscape(*c.bucket + "/" + key1)), PartNumber: aws.Int64(1), Key: &key3, UploadId: uploadID, }) // ...第二次调用 PartNumber 为 aws.Int64(2),源对象为 key2这里最值得注意的细节是CopySource必须 URL 编码:url.QueryEscape(*c.bucket + "/" + key1)把桶名/对象Key拼接成形如my-bucket/prefix/obj1的源路径并做转义。service/s3/api.go 中该字段的注释明确要求:"The value must be URL-encoded",并允许通过?versionId=<version-id>指定拷贝某个具体版本。
PartNumber是分片编号,service/s3/api.go 注释规定其为 1 到 10,000 之间的正整数且为必填字段。拼接顺序即由 PartNumber 决定:分片 1 在前、分片 2 在后,最终对象内容为 对象1 + 对象2。
第 3 步:提交分片上传(CompleteMultipartUpload)
两次拷贝成功后,concatenate从每次响应的CopyPartResult.ETag中取出实体标签并返回:
return foo.CopyPartResult.ETag, bar.CopyPartResult.ETag, nilmain用这两个 ETag 组装CompletedMultipartUpload,调用CompleteMultipartUpload完成拼接:
_, err = c.s3Client.CompleteMultipartUpload(&s3.CompleteMultipartUploadInput{ Bucket: &bucket, Key: &key3, UploadId: output.UploadId, MultipartUpload: &s3.CompletedMultipartUpload{ Parts: []*s3.CompletedPart{ {ETag: foo, PartNumber: aws.Int64(1)}, {ETag: bar, PartNumber: aws.Int64(2)}, }, }, })ETag 是服务端对分片内容生成的校验标识,必须原样回传给完成请求。CompletedMultipartUpload的定义见 service/s3/api.go,其注释提醒:如果提交的分片信息不合法,服务端会返回 HTTP 400。
五、UploadPartCopyInput 参数深度解析
UploadPartCopyInput结构体(定义于 service/s3/api.go)包含以下主要字段,示例只使用了其中一小部分,其余可按需扩展:
| 字段 | 位置(Header/URI/Query) | 必填 | 说明 |
|---|---|---|---|
Bucket | URI | 是 | 目标桶名,支持目录桶、访问点 ARN、S3 on Outposts 等寻址形式 |
Key | URI | 是 | 分片上传对应的目标对象 Key,最小长度 1 |
UploadId | Query | 是 | 由CreateMultipartUpload返回的分片上传标识 |
CopySource | x-amz-copy-source | 是 | 源对象路径,格式为桶名/Key且必须 URL 编码,可用?versionId=指定版本 |
PartNumber | Query | 是 | 分片编号,1 ~ 10,000 |
CopySourceRange | x-amz-copy-source-range | 否 | 字节范围,格式bytes=first-last(零基偏移),仅当源对象大于 5 MB 时才可使用,用于"大对象拆片拷贝" |
CopySourceIfMatch/CopySourceIfNoneMatch | Header | 否 | 按源对象 ETag 做前置条件校验,不满足返回 412 |
CopySourceIfModifiedSince/CopySourceIfUnmodifiedSince | Header | 否 | 按源对象修改时间做前置条件校验 |
CopySourceSSECustomerAlgorithm/CopySourceSSECustomerKey/CopySourceSSECustomerKeyMD5 | Header | 否 | 源对象使用 SSE-C 加密时的解密算法、密钥与 MD5 |
SSECustomerAlgorithm/SSECustomerKey | Header | 否 | 目标分片使用 SSE-C 加密时的加密参数 |
ExpectedBucketOwner/ExpectedSourceBucketOwner | Header | 否 | 期望的桶属主账号 ID,不匹配时返回 403 |
RequestPayer | x-amz-request-payer | 否 | Requester Pays 桶场景下的付费确认 |
拷贝成功后返回UploadPartCopyOutput.CopyPartResult,其结构(service/s3/api.go)包含ETag、LastModified,以及ChecksumCRC32、ChecksumCRC32C、ChecksumSHA1、ChecksumSHA256等完整性校验值(多分片对象的校验值是各分片校验值的聚合计算)。
六、进阶用法:从"整对象拼接"到"字节范围拼接"
示例演示的是每个分片对应一个完整对象,而UploadPartCopy的能力不止于此。仓库自带的单元示例 service/s3/examples_test.go 给出了两种典型调用:
- 整对象拷贝(
ExampleS3_UploadPartCopy_shared00):CopySource直接指定/bucketname/sourceobjectkey,PartNumber为 1; - 字节范围拷贝(
ExampleS3_UploadPartCopy_shared01):增加CopySourceRange: aws.String("bytes=1-100000"),将源对象 1 ~ 100,000 字节区间作为一个分片。
组合这两者,即可把"超大对象拆成多个分片再拼接"或"按任意字节边界裁切后重组"等场景纳入同一条流水线。需要特别注意的是:使用CopySourceRange时,源对象大小必须大于 5 MB(见 service/s3/api.go 的注释约束)。
七、错误处理与可观测性
示例中所有 API 调用失败都会以log.Println("ERROR:", err)输出并终止程序。在生产代码中,建议使用 SDK 的错误类型断言来区分服务端错误与本地错误:
if aerr, ok := err.(awserr.Error); ok { switch aerr.Code() { default: log.Println(aerr.Error()) } }这种模式同样出现在 service/s3/examples_test.go 的示例测试中。常见的失败场景包括:凭证或权限不足(403)、CopySource未正确 URL 编码或对象不存在(404)、提交的分片列表不完整/ETag 不匹配(400)、目标桶开启了 Requester Pays 而未设置RequestPayer等。
八、适用边界与注意事项
- 拼接顺序即分片顺序:输出对象的字节内容严格按照
PartNumber升序组装,示例中对象 1 在前、对象 2 在后; - 对象数量可扩展:示例固定为两个分片,但
CompletedMultipartUpload.Parts是数组,按此模式可扩展到任意多个对象的顺序拼接; - 分片数量上限:单个分片上传任务最多包含 10,000 个分片(
PartNumber上限),且每个分片有最小/最大尺寸约束,相关规范见 API 注释中引用的 Multipart upload limits; - 数据一致性:分片上传的最终对象 ETag 是各分片 ETag 的聚合结果,而非简单拼接的哈希,校验时应以
CompleteMultipartUpload返回的 ETag 为准; - 废弃状态提醒:本仓库 go.mod 已标注
aws-sdk-go(v1)进入废弃状态,官方建议新项目迁移到 AWS SDK for Go v2,但 v1 的 S3 分片拷贝调用链与本文所述的 HTTP 语义完全一致,仍适用于维护存量代码的场景。
九、源码阅读指引
如果想进一步研究实现细节,建议按以下路径阅读仓库源码:
- example/service/s3/concatObjects/concatObjects.go:示例完整源码,验证本文所述的三段式调用链;
- service/s3/api.go:
UploadPartCopyRequest/UploadPartCopy的实现,可看到底层PUT /{Bucket}/{Key+}的请求构造; - service/s3/api.go:
CompleteMultipartUploadInput及其校验字段(CRC32/SHA 系列); - service/s3/examples_test.go:
UploadPartCopy的整对象与字节范围两种官方示例用法; - aws/session/session.go:会话与凭证加载机制,理解
session.New(&aws.Config{})的行为。
通过本文,你可以直接运行该示例完成"两个对象拼接成一个对象"的验证,并以此为基础,把UploadPartCopy的分片拷贝能力延伸到多对象聚合、超大对象拆分重组等更复杂的服务端数据编排场景。
- 后端
- 云原生
- 开发工具
【免费下载链接】aws-sdk-go
This SDK has reached end-of-support. The AWS SDK for Go v2 is available here: https://github.com/aws/aws-sdk-go-v2
相关推荐
使用 AWS SDK for Java 2.x 实现 Amazon S3 对象锁全流程:aws-doc-sdk-examples 的 Object Lock 工作流示例
使用 AWS SDK for Java 2.x 实现 Amazon S3 对象锁全流程:aws doc sdk examples 的 Object Lock 工
示例工程教程后端lucide-react 图标库完整指南:3 步接入 React 并自由定制外观
lucide react 图标库完整指南:3 步接入 React 并自由定制外观 Lucide 是社区驱动的开源图标工具包, lucide react 是其官方
前端UI组件设计系统AWS SDK for JavaScript v3 中的 Amazon S3 代码示例解析
AWS SDK for JavaScript v3 中的 Amazon S3 代码示例解析 概述 Amazon Simple Storage Service A
示例工程教程后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考