1package cos 2 3import ( 4 "context" 5 "encoding/xml" 6 "fmt" 7 "io" 8 "net/http" 9 "net/url" 10) 11 12// ObjectService ... 13// 14// Object 相关 API 15type ObjectService service 16 17// ObjectGetOptions ... 18// 19// https://cloud.tencent.com/document/product/436/7753 20type ObjectGetOptions struct { 21 // 设置响应头部中的 Content-Type 参数 22 ResponseContentType string `url:"response-content-type,omitempty" header:"-"` 23 // 设置响应头部中的 Content-Language 参数 24 ResponseContentLanguage string `url:"response-content-language,omitempty" header:"-"` 25 // 设置响应头部中的 Content-Expires 参数 26 ResponseExpires string `url:"response-expires,omitempty" header:"-"` 27 // 设置响应头部中的 Cache-Control 参数 28 ResponseCacheControl string `url:"response-cache-control,omitempty" header:"-"` 29 // 设置响应头部中的 Content-Disposition 参数 30 ResponseContentDisposition string `url:"response-content-disposition,omitempty" header:"-"` 31 // 设置响应头部中的 Content-Encoding 参数 32 ResponseContentEncoding string `url:"response-content-encoding,omitempty" header:"-"` 33 // RFC 2616 中定义的指定文件下载范围,以字节(bytes)为单位 34 Range string `url:"-" header:"Range,omitempty"` 35 // 如果文件修改时间早于或等于指定时间,才返回文件内容。否则返回 412 (precondition failed) 36 IfUnmodifiedSince string `url:"-" header:"If-Unmodified-Since,omitempty"` 37 // 当 Object 在指定时间后被修改,则返回对应 Object meta 信息,否则返回 304(not modified) 38 IfModifiedSince string `url:"-" header:"If-Modified-Since,omitempty"` 39 // 当 ETag 与指定的内容一致,才返回文件。否则返回 412 (precondition failed) 40 IfMatch string `url:"-" header:"If-Match,omitempty"` 41 // 当 ETag 与指定的内容不一致,才返回文件。否则返回 304 (not modified) 42 IfNoneMatch string `url:"-" header:"If-None-Match,omitempty"` 43 44 // 预签名授权 URL 45 PresignedURL *url.URL `header:"-" url:"-" xml:"-"` 46} 47 48// MethodObjectGet method name of Object.Get 49const MethodObjectGet MethodName = "Object.Get" 50 51// Get Object 请接口请求可以在 COS 的存储桶中将一个文件(对象)下载至本地。 52// 该操作需要请求者对目标对象具有读权限或目标对象对所有人都开放了读权限(公有读)。 53// 54// 版本 55// 56// 当启用多版本,该 GET 操作返回对象的当前版本。要返回不同的版本,请使用 versionId 参数。 57// 58// 注意 59// 60// 如果该对象的当前版本是删除标记,则 COS 的行为表现为该对象不存在,并返回响应 x-cos-delete-marker: true。 61// 62// https://cloud.tencent.com/document/product/436/7753 63func (s *ObjectService) Get(ctx context.Context, name string, opt *ObjectGetOptions) (*Response, error) { 64 baseURL := s.client.BaseURL.BucketURL 65 uri := "/" + encodeURIComponent(name) 66 if opt != nil && opt.PresignedURL != nil { 67 baseURL = opt.PresignedURL 68 uri = "" 69 } 70 sendOpt := sendOptions{ 71 baseURL: baseURL, 72 uri: uri, 73 method: http.MethodGet, 74 optQuery: opt, 75 optHeader: opt, 76 disableCloseBody: true, 77 caller: Caller{ 78 Method: MethodObjectGet, 79 }, 80 } 81 resp, err := s.client.send(ctx, &sendOpt) 82 return resp, err 83} 84 85// ObjectPutHeaderOptions ... 86type ObjectPutHeaderOptions struct { 87 // RFC 2616 中定义的缓存策略,将作为 Object 元数据保存。 88 CacheControl string `header:"Cache-Control,omitempty" url:"-"` 89 // RFC 2616 中定义的文件名称,将作为 Object 元数据保存。 90 ContentDisposition string `header:"Content-Disposition,omitempty" url:"-"` 91 // RFC 2616 中定义的编码格式,将作为 Object 元数据保存。 92 ContentEncoding string `header:"Content-Encoding,omitempty" url:"-"` 93 // RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存。 94 ContentType string `header:"Content-Type,omitempty" url:"-"` 95 // 96 ContentLength int `header:"Content-Length,omitempty" url:"-"` 97 // RFC 2616 中定义的文件日期和时间,将作为 Object 元数据保存。 98 Expect string `header:"Expect,omitempty" url:"-"` 99 Expires string `header:"Expires,omitempty" url:"-"` 100 XCosContentSHA1 string `header:"x-cos-content-sha1,omitempty" url:"-"` 101 // 自定义的 x-cos-meta-* header 102 // 包括用户自定义头部后缀和用户自定义头部信息,将作为 Object 元数据返回,大小限制为 2KB。 103 // 注意:用户自定义头部信息支持下划线,但用户自定义头部后缀不支持下划线。 104 XCosMetaXXX *http.Header `header:"x-cos-meta-*,omitempty" url:"-"` 105 // 设置 Object 的存储级别,枚举值:STANDARD, STANDARD_IA,默认值:STANDARD 106 XCosStorageClass string `header:"x-cos-storage-class,omitempty" url:"-"` 107 108 // XCosServerSideEncryption 用于指定腾讯云 COS 在数据存储时,应用数据加密的保护策略。 109 // 腾讯云 COS 会帮助您在数据写入数据中心时自动加密,并在您取用该数据时自动解密。 110 // 目前支持使用腾讯云 COS 主密钥对数据进行 AES-256 加密。 111 // 如果您需要对数据启用服务端加密,则需指定 XCosServerSideEncryption。 112 // 113 // 指定将对象启用服务端加密的方式。使用 COS 主密钥加密填写:AES256 114 XCosServerSideEncryption string `header:"x-cos-server-side-encryption,omitempty" url:"-"` 115 // 可选值: Normal, Appendable 116 //XCosObjectType string `header:"x-cos-object-type,omitempty" url:"-"` 117} 118 119// ObjectPutOptions ... 120type ObjectPutOptions struct { 121 *ACLHeaderOptions `header:",omitempty" url:"-" xml:"-"` 122 *ObjectPutHeaderOptions `header:",omitempty" url:"-" xml:"-"` 123 124 // 预签名授权 URL 125 PresignedURL *url.URL `header:"-" url:"-" xml:"-"` 126} 127 128// MethodObjectPut method name of Object.Put 129const MethodObjectPut MethodName = "Object.Put" 130 131// Put Object请求可以将一个文件(Object)上传至指定Bucket。 132// 133// 版本 134// 135// * 如果对存储桶启用版本控制,对象存储将自动为要添加的对象生成唯一的版本 ID。 136// 对象存储使用 x-cos-version-id 响应头部在响应中返回此标识。 137// * 如果需要暂停存储桶的版本控制,则对象存储始终将其 null 用作存储在存储桶中的对象的版本 ID。 138// 139// 细节分析 140// 141// * 需要有 Bucket 的写权限; 142// * 如果请求头的 Content-Length 值小于实际请求体(body)中传输的数据长度,COS 仍将成功创建文件, 143// 但 Object 大小只等于 Content-Length 中定义的大小,其他数据将被丢弃; 144// * 如果试图添加的 Object 的同名文件已经存在,那么新上传的文件,将覆盖原来的文件,成功时返回 200 OK。 145// 146// 当 r 是个 io.ReadCloser 时 Put 方法不会自动调用 r.Close(),用户需要自行选择合适的时机去调用 r.Close() 方法对 r 进行资源回收 147// 148// https://cloud.tencent.com/document/product/436/7749 149func (s *ObjectService) Put(ctx context.Context, name string, r io.Reader, opt *ObjectPutOptions) (*Response, error) { 150 baseURL := s.client.BaseURL.BucketURL 151 uri := "/" + encodeURIComponent(name) 152 if opt != nil && opt.PresignedURL != nil { 153 baseURL = opt.PresignedURL 154 uri = "" 155 } 156 sendOpt := sendOptions{ 157 baseURL: baseURL, 158 uri: uri, 159 method: http.MethodPut, 160 body: r, 161 optHeader: opt, 162 caller: Caller{ 163 Method: MethodObjectPut, 164 }, 165 } 166 resp, err := s.client.send(ctx, &sendOpt) 167 return resp, err 168} 169 170// ObjectCopyHeaderOptions ... 171// https://cloud.tencent.com/document/product/436/10881 172type ObjectCopyHeaderOptions struct { 173 // 是否拷贝源文件的元数据,枚举值:Copy, Replaced,默认值 Copy。假如标记为 Copy, 174 // 则拷贝源文件的元数据;假如标记为 Replaced,则按本次请求的 Header 信息修改元数据。 175 // 当目标路径和源路径一致,即用户试图修改元数据时,则标记必须为 Replaced。 176 XCosMetadataDirective string `header:"x-cos-metadata-directive,omitempty" url:"-" xml:"-"` 177 // 当 Object 在指定时间后被修改,则执行操作,否则返回 412。 178 // 可与 XCosCopySourceIfNoneMatch 一起使用,与其他条件联合使用返回冲突。 179 XCosCopySourceIfModifiedSince string `header:"x-cos-copy-source-If-Modified-Since,omitempty" url:"-" xml:"-"` 180 // 当 Object 在指定时间后未被修改,则执行操作,否则返回 412。 181 // 可与 XCosCopySourceIfMatch 一起使用,与其他条件联合使用返回冲突。 182 XCosCopySourceIfUnmodifiedSince string `header:"x-cos-copy-source-If-Unmodified-Since,omitempty" url:"-" xml:"-"` 183 // 当 Object 的 Etag 和给定一致时,则执行操作,否则返回 412。 184 // 可与 XCosCopySourceIfUnmodifiedSince 一起使用,与其他条件联合使用返回冲突。 185 XCosCopySourceIfMatch string `header:"x-cos-copy-source-If-Match,omitempty" url:"-" xml:"-"` 186 // 当 Object 的 Etag 和给定不一致时,则执行操作,否则返回 412。 187 // 可与 XCosCopySourceIfModifiedSince 一起使用,与其他条件联合使用返回冲突。 188 XCosCopySourceIfNoneMatch string `header:"x-cos-copy-source-If-None-Match,omitempty" url:"-" xml:"-"` 189 // 设置 Object 的存储级别,枚举值:STANDARD,STANDARD_IA。默认值:STANDARD 190 XCosStorageClass string `header:"x-cos-storage-class,omitempty" url:"-" xml:"-"` 191 // 自定义的 x-cos-meta-* header 192 XCosMetaXXX *http.Header `header:"x-cos-meta-*,omitempty" url:"-"` 193 // 源文件 URL 路径,可以通过 versionid 子资源指定历史版本 194 XCosCopySource string `header:"x-cos-copy-source" url:"-" xml:"-"` 195 196 // XCosServerSideEncryption 用于指定腾讯云 COS 在数据存储时,应用数据加密的保护策略。 197 // 腾讯云 COS 会帮助您在数据写入数据中心时自动加密,并在您取用该数据时自动解密。 198 // 目前支持使用腾讯云 COS 主密钥对数据进行 AES-256 加密。 199 // 如果您需要对数据启用服务端加密,则需指定 XCosServerSideEncryption。 200 // 201 // 指定将对象启用服务端加密的方式。使用 COS 主密钥加密填写:AES256 202 XCosServerSideEncryption string `header:"x-cos-server-side-encryption,omitempty" url:"-"` 203} 204 205// ObjectCopyOptions ... 206// 207// https://cloud.tencent.com/document/product/436/10881 208type ObjectCopyOptions struct { 209 *ObjectCopyHeaderOptions `header:",omitempty" url:"-" xml:"-"` 210 *ACLHeaderOptions `header:",omitempty" url:"-" xml:"-"` 211} 212 213// ObjectCopyResult ... 214type ObjectCopyResult struct { 215 XMLName xml.Name `xml:"CopyObjectResult"` 216 // 返回文件的 MD5 算法校验值。ETag 的值可以用于检查 Object 的内容是否发生变化。 217 ETag string `xml:"ETag,omitempty"` 218 // 返回文件最后修改时间,GMT 格式 219 LastModified string `xml:"LastModified,omitempty"` 220} 221 222// MethodObjectCopy method name of Object.Copy 223const MethodObjectCopy MethodName = "Object.Copy" 224 225// Copy ... 226// 227// Put Object Copy 请求实现将一个文件从源路径复制到目标路径。建议文件大小 1M 到 5G, 228// 超过 5G 的文件请使用分块上传 Upload - Copy。在拷贝的过程中,文件元属性和 ACL 可以被修改。 229// 230// 用户可以通过该接口实现文件移动,文件重命名,修改文件属性和创建副本。 231// 232// 版本 233// 234// * 默认情况下,在目标存储桶上启用版本控制,对象存储会为正在复制的对象生成唯一的版本 ID。此版本 ID 与源对象的版本 ID 不同。 235// 对象存储会在 x-cos-version-id 响应中的响应标头中返回复制对象的版本 ID。 236// * 如果您在目标存储桶没有启用版本控制或暂停版本控制,则对象存储生成的版本 ID 始终为 null。 237// 238// 注意:在跨帐号复制的时候,需要先设置被复制文件的权限为公有读,或者对目标帐号赋权,同帐号则不需要。 239// 240// https://cloud.tencent.com/document/product/436/10881 241func (s *ObjectService) Copy(ctx context.Context, name, sourceURL string, opt *ObjectCopyOptions) (*ObjectCopyResult, *Response, error) { 242 var res ObjectCopyResult 243 if opt == nil { 244 opt = new(ObjectCopyOptions) 245 } 246 if opt.ObjectCopyHeaderOptions == nil { 247 opt.ObjectCopyHeaderOptions = new(ObjectCopyHeaderOptions) 248 } 249 opt.XCosCopySource = sourceURL 250 251 sendOpt := sendOptions{ 252 baseURL: s.client.BaseURL.BucketURL, 253 uri: "/" + encodeURIComponent(name), 254 method: http.MethodPut, 255 body: nil, 256 optHeader: opt, 257 result: &res, 258 caller: Caller{ 259 Method: MethodObjectCopy, 260 }, 261 } 262 resp, err := s.client.send(ctx, &sendOpt) 263 return &res, resp, err 264} 265 266// MethodObjectDelete method name of Object.Delete 267const MethodObjectDelete MethodName = "Object.Delete" 268 269// Delete Object 接口请求可以在 COS 的 Bucket 中将一个文件(Object)删除。该操作需要请求者对 Bucket 有 WRITE 权限。 270// 271// 细节分析 272// 273// * 在 DELETE Object 请求中删除一个不存在的 Object,仍然认为是成功的,返回 204 No Content。 274// * DELETE Object 要求用户对该 Object 要有写权限。 275// 276// https://cloud.tencent.com/document/product/436/7743 277func (s *ObjectService) Delete(ctx context.Context, name string) (*Response, error) { 278 sendOpt := sendOptions{ 279 baseURL: s.client.BaseURL.BucketURL, 280 uri: "/" + encodeURIComponent(name), 281 method: http.MethodDelete, 282 caller: Caller{ 283 Method: MethodObjectDelete, 284 }, 285 } 286 resp, err := s.client.send(ctx, &sendOpt) 287 return resp, err 288} 289 290// ObjectHeadOptions ... 291type ObjectHeadOptions struct { 292 // 当 Object 在指定时间后被修改,则返回对应 Object 的 meta 信息,否则返回 304 293 IfModifiedSince string `url:"-" header:"If-Modified-Since,omitempty"` 294} 295 296// MethodObjectHead method name of Object.Head 297const MethodObjectHead MethodName = "Object.Head" 298 299// Head Object请求可以取回对应Object的元数据,Head的权限与Get的权限一致 300// 301// 默认情况下,HEAD 操作从当前版本的对象中检索元数据。如要从不同版本检索元数据,请使用 versionId 子资源。 302// 303// https://cloud.tencent.com/document/product/436/7745 304func (s *ObjectService) Head(ctx context.Context, name string, opt *ObjectHeadOptions) (*Response, error) { 305 sendOpt := sendOptions{ 306 baseURL: s.client.BaseURL.BucketURL, 307 uri: "/" + encodeURIComponent(name), 308 method: http.MethodHead, 309 optHeader: opt, 310 caller: Caller{ 311 Method: MethodObjectHead, 312 }, 313 } 314 resp, err := s.client.send(ctx, &sendOpt) 315 return resp, err 316} 317 318// ObjectOptionsOptions ... 319// 320// https://cloud.tencent.com/document/product/436/8288 321type ObjectOptionsOptions struct { 322 // 模拟跨域访问的请求来源域名,必选 323 Origin string `url:"-" header:"Origin"` 324 // 模拟跨域访问的请求 HTTP 方法,必选 325 AccessControlRequestMethod string `url:"-" header:"Access-Control-Request-Method"` 326 // 模拟跨域访问的请求头部 327 AccessControlRequestHeaders string `url:"-" header:"Access-Control-Request-Headers,omitempty"` 328} 329 330// MethodObjectOptions method name of Object.Options 331const MethodObjectOptions MethodName = "Object.Options" 332 333// Options Object 接口实现 Object 跨域访问配置的预请求。 334// 即在发送跨域请求之前会发送一个 OPTIONS 请求并带上特定的来源域,HTTP 方法和 Header 信息等给 COS, 335// 以决定是否可以发送真正的跨域请求。当 CORS 配置不存在时,请求返回 403 Forbidden。 336// 可以通过 PUT Bucket cors 接口来开启 Bucket 的 CORS 支持。 337// 338// https://cloud.tencent.com/document/product/436/8288 339func (s *ObjectService) Options(ctx context.Context, name string, opt *ObjectOptionsOptions) (*Response, error) { 340 sendOpt := sendOptions{ 341 baseURL: s.client.BaseURL.BucketURL, 342 uri: "/" + encodeURIComponent(name), 343 method: http.MethodOptions, 344 optHeader: opt, 345 caller: Caller{ 346 Method: MethodObjectOptions, 347 }, 348 } 349 resp, err := s.client.send(ctx, &sendOpt) 350 return resp, err 351} 352 353// MethodObjectAppend method name of Object.Append 354const MethodObjectAppend MethodName = "Object.Append" 355 356// Append ... 357// 358// Append请求可以将一个文件(Object)以分块追加的方式上传至 Bucket 中。使用Append Upload的文件必须事前被设定为Appendable。 359// 当Appendable的文件被执行Put Object的操作以后,文件被覆盖,属性改变为Normal。 360// 361// 文件属性可以在Head Object操作中被查询到,当您发起Head Object请求时,会返回自定义Header『x-cos-object-type』,该Header只有两个枚举值:Normal或者Appendable。 362// 363// 追加上传建议文件大小1M - 5G。如果position的值和当前Object的长度不致,COS会返回409错误。 364// 如果Append一个Normal的Object,COS会返回409 ObjectNotAppendable。 365// 366// Appendable的文件不可以被复制,不参与版本管理,不参与生命周期管理,不可跨区域复制。 367// 368// 当 r 不是 bytes.Buffer/bytes.Reader/strings.Reader 时,必须指定 opt.ObjectPutHeaderOptions.ContentLength 369// 当 r 是个 io.ReadCloser 时 Append 方法不会自动调用 r.Close(),用户需要自行选择合适的时机去调用 r.Close() 方法对 r 进行资源回收 370// 371// https://www.qcloud.com/document/product/436/7741 372func (s *ObjectService) Append(ctx context.Context, name string, position int, r io.Reader, opt *ObjectPutOptions) (*Response, error) { 373 u := fmt.Sprintf("/%s?append&position=%d", encodeURIComponent(name), position) 374 sendOpt := sendOptions{ 375 baseURL: s.client.BaseURL.BucketURL, 376 uri: u, 377 method: http.MethodPost, 378 optHeader: opt, 379 body: r, 380 caller: Caller{ 381 Method: MethodObjectAppend, 382 }, 383 } 384 resp, err := s.client.send(ctx, &sendOpt) 385 return resp, err 386} 387 388// ObjectDeleteMultiOptions ... 389// 390// https://cloud.tencent.com/document/product/436/8289 391type ObjectDeleteMultiOptions struct { 392 XMLName xml.Name `xml:"Delete" header:"-"` 393 // 布尔值,这个值决定了是否启动 Quiet 模式。 394 // 值为 true 启动 Quiet 模式,值为 false 则启动 Verbose 模式,默认值为 False 395 Quiet bool `xml:"Quiet" header:"-"` 396 // 说明每个将要删除的目标 Object 信息,只需指定 Key 即可 397 Objects []Object `xml:"Object" header:"-"` 398 //XCosSha1 string `xml:"-" header:"x-cos-sha1"` 399} 400 401// ObjectDeleteMultiResult ... 402// 403// https://cloud.tencent.com/document/product/436/8289 404type ObjectDeleteMultiResult struct { 405 XMLName xml.Name `xml:"DeleteResult"` 406 // 说明本次删除的成功 Object 信息 407 DeletedObjects []Object `xml:"Deleted,omitempty"` 408 // 说明本次删除的失败 Object 信息 409 Errors []struct { 410 // 删除失败的 Object 的名称 411 Key string 412 // 删除失败的错误代码 413 Code string 414 // 删除失败的错误信息 415 Message string 416 } `xml:"Error,omitempty"` 417} 418 419// MethodObjectDeleteMulti method name of Object.DeleteMulti 420const MethodObjectDeleteMulti MethodName = "Object.DeleteMulti" 421 422// DeleteMulti ... 423// 424// Delete Multiple Object请求实现批量删除文件,最大支持单次删除1000个文件。 425// 对于返回结果,COS提供Verbose和Quiet两种结果模式。Verbose模式将返回每个Object的删除结果; 426// Quiet模式只返回报错的Object信息。 427// 428// 细节分析 429// 430// * 每一个批量删除请求,最多只能包含 1000个 需要删除的对象; 431// * 批量删除支持二种模式的放回,verbose 模式和 quiet 模式,默认为 verbose 模式。 432// verbose 模式返回每个 key 的删除情况,quiet 模式只返回删除失败的 key 的情况; 433// * 批量删除需要携带 Content-MD5 头部,用以校验请求 body 没有被修改; 434// * 批量删除请求允许删除一个不存在的 key,仍然认为成功。 435// 436// https://cloud.tencent.com/document/product/436/8289 437func (s *ObjectService) DeleteMulti(ctx context.Context, opt *ObjectDeleteMultiOptions) (*ObjectDeleteMultiResult, *Response, error) { 438 var res ObjectDeleteMultiResult 439 sendOpt := sendOptions{ 440 baseURL: s.client.BaseURL.BucketURL, 441 uri: "/?delete", 442 method: http.MethodPost, 443 body: opt, 444 result: &res, 445 caller: Caller{ 446 Method: MethodObjectDeleteMulti, 447 }, 448 } 449 resp, err := s.client.send(ctx, &sendOpt) 450 return &res, resp, err 451} 452 453type objectPresignedURLTestingOptions struct { 454 authTime *AuthTime 455} 456 457// PresignedURL 生成预签名授权 URL,可用于无需知道 SecretID 和 SecretKey 就可以上传和下载文件 。 458// 459// httpMethod: 460// * 下载文件:http.MethodGet 461// * 上传文件: http.MethodPut 462// 463// 下载文件 时 opt 可以是 *ObjectGetOptions ,上传文件时 opt 可以是 *ObjectPutOptions 464// 465// https://cloud.tencent.com/document/product/436/14116 466// https://cloud.tencent.com/document/product/436/14114 467func (s *ObjectService) PresignedURL(ctx context.Context, httpMethod, name string, auth Auth, opt interface{}) (*url.URL, error) { 468 sendOpt := sendOptions{ 469 baseURL: s.client.BaseURL.BucketURL, 470 uri: "/" + encodeURIComponent(name), 471 method: httpMethod, 472 optQuery: opt, 473 optHeader: opt, 474 } 475 req, err := s.client.newRequest(ctx, &sendOpt) 476 if err != nil { 477 return nil, err 478 } 479 480 var authTime *AuthTime 481 if opt != nil { 482 if opt, ok := opt.(*objectPresignedURLTestingOptions); ok { 483 authTime = opt.authTime 484 } 485 } 486 if authTime == nil { 487 authTime = NewAuthTime(auth.Expire) 488 } 489 authorization := newAuthorization(auth, req, *authTime) 490 sign := encodeURIComponent(authorization) 491 492 if req.URL.RawQuery == "" { 493 req.URL.RawQuery = fmt.Sprintf("sign=%s", sign) 494 } else { 495 req.URL.RawQuery = fmt.Sprintf("%s&sign=%s", req.URL.RawQuery, sign) 496 } 497 return req.URL, nil 498} 499 500// Object ... 501type Object struct { 502 // Object 的 Key 503 Key string `xml:",omitempty"` 504 // 文件的 MD-5 算法校验值 505 ETag string `xml:",omitempty"` 506 // 说明文件大小,单位是 Byte 507 Size int `xml:",omitempty"` 508 // 块编号 509 PartNumber int `xml:",omitempty"` 510 // 说明 Object 最后被修改时间 511 LastModified string `xml:",omitempty"` 512 // Object 的存储级别,枚举值:STANDARD,STANDARD_IA,ARCHIVE 513 StorageClass string `xml:",omitempty"` 514 // Bucket 持有者信息 515 Owner *Owner `xml:",omitempty"` 516} 517