OpenStack Object Storage Developer Guide/Swift官方API文档 -- 翻译 ,四

3.4. 对象存储服务(Storage Object Services)

一个对象(Object)是存储在系统中的一个文件数据和这个文件的元数据。通过ReST接口,我们可以使用HTTP的自定义headers来包含对象的元数据、HTTP的消息体(body)来包含数据实际的有效荷载。对象的大小不能超过5GB,且对象的名字在经过URL编码后不能超过1024个字节。然而,对于大于5GB的对象,我们可以将其分段,然后再将对象片段串联起来,这样就可以实现分段上传5GB以内的对象,并在下载时下载一个大于5GB的串联对象了。你可以直接使用HTTP请求来处理分段并管理好分段之间的组合关系。

3.4.1. 获取对象

在object上执行GET操作可以获取对象的数据。

请注意,你可以使用 RFC2616 中指定的特定的HTTP头信息来执行有条件的GET请求。OpenStack对象存储支持以下headers:

  • If-Match
  • If-None-Match
  • If-Modified-Since
  • If-Unmodified-Since

你也可以使用HTTP的 Range 头来获取一部分的数据。目前,Swift还不支持完整的Range定义,但是基本的功能是支持的:只支持使用 OFFSETLENGTH 来实现一个范围的获取。由于我们只实现了Range的子集,因此在这里不再列出RFC-2616中Range的完整定义。我们支持指定偏OFFSET和LENGTH,这两者是可选的,可选择其中一个指定,但不支持同时指定。以下是支持的头形式:

  • Range: bytes=-5 —— 对象的最后5个字节
  • Range: bytes=10-15 —— 偏移10个字节后的连续5个字节,11 ~ 15个字节
  • Range: bytes=32- —— 开始32个字节之后的所有数据

  例 3.43. 获取对象的请求

GET /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb

请求的对象数据将会包含在响应消息体中,对象的元数据将会以HTTP头信息的形式返回。状态码200(OK)表明请求成功,状态码404(Not Found)表明请求的对象不存在。

  例 3.44. 获取对象的响应

HTTP/1.1 200 Ok
Date: Wed, 11 Jul 2010 19:37:41 GMT
Server: Apache
Last-Modified: Fri, 12 Jun 2010 13:40:18 GMT
ETag: b0dffe8254d152d8fd28f3c5e0404a10
Content-type: text/html
Content-Length: 512000
[ ... ]

3.4.2. 创建/更新对象

使用PUT操作可以对一个对象的数据和元数据进行写、重写。

你可以使用对象数据的MD5 checksum值来保证数据在不同端的完整性,这个checksum被存储在对象的 ETag 头信息中。系统不要求你一定要包含ETag头,但是我们推荐你使用这个值来确定你所创建/更新的对象是否成功的被保存(本地的Checksun值为A,操作后系统返回ETag值为B,如果A == B,则对象保存成功,如果不相等,则保存的内容与本地上传的内容不同)。

HTTP响应消息将包含被写入存储系统的数据的MD5校验值。如果你没有在请求中发送ETag,则应该将返回的ETag值与本地的数据进行MD5校验值的比较,以确保数据在端到端之间是一致的。对于分段的对象,整个对象的ETag值是这个对象的每个段的ETag值的和,因此被分段的对象的ETag值只提供对象变更的监测,而无法提供对象间的比较功能。

我们还可以使用附带额外headers的PUT请求为objects关联自定义的元数据信息。

我们可以使用形如 X-Object-Meta-prefix 的HTTP头信息来创建包含自定义元数据的对象。

  例 3.45. 创建/更新对象的请求

PUT /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
ETag: 8a964ee2a5e88be344f36c22562a6486
Content-Length: 512000
X-Object-Meta-PIN: 1234
[ ... ]

一个没有消息体的响应将会被返回。状态码201(Created)表示写入成功;状态码411(Length Required)表示请求消息中没有包含 Content-LengthContent-Type header;如果最终将写入swift的数据的MD5校验值与请求时提供的ETag(可选的)不匹配,则状态码为422(Unprecessable Entity)表明对象没有被实际写入。

  例 3.46. 创建/更新对象的响应

HTTP/1.1 201 Created
Date: Thu, 07 Jun 2010 18:57:07 GMT
Server: Apache
ETag: d9f5eb4bba4e2f2f046e54611bc8196b
Content-Length: 0
Content-Type: text/plain; charset=UTF-8

3.4.2.1. 大对象的创建

大于5GB的对象在上传之前需要被分段。分段后,你就可以像上传其他普通对象一样对这些分了端的objects进行上传,此外,你还需要创建一张清单(manifest)来说明如何在swift中查找到该大对象的各个分段。这些分段对象拥有独立的访问地址,但可以被manifest检索形成连续的对象流。一个大对象的分段的数量是没有限制的。

为了确保下载工作的正确执行,你必须将所有的分段对象上传到同一个容器中、使用相同的命名前缀,并将其按照在大对象中的顺序进行命名。同时,你也需要创建并上传一个清单文件。这个清单文件仅仅是一个0字节大小的空文件,但是包含额外且重要的元数据信息:X-Object-Manifest: <container>/<prefix>。其中<container>是分段对象所存储的容器名称,<prefix>是所有分段对象的公共前缀。

你最好先上传所有的分段对象,再创建或更新清单文件。使用这种方法,可以保证在完整的大对象上传完毕前,该对象是不可以被访问的,从而避免一个大对象被同时读写造成的不一致错误。此外,你也可以上传一些新分段到另外位置,并更新清单将其指向这个新的地址。在上传新分段的过程中,原来的清单文件仍然是可访问的,因此此时可以下载到原先的分段对象。

  例 3.47. 上传大对象的分段

PUT /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
ETag: 8a964ee2a5e88be344f36c22562a6486
Content-Length: 1
X-Object-Meta-PIN: 1234
s

一个没有消息体的响应将会被返回。状态码201(Created)表示写入成功;状态码411(Length Required)表示请求消息中没有包含 Content-LengthContent-Type header;如果最终将写入swift的数据的MD5校验值与请求时提供的ETag(可选的)不匹配,则状态码为422(Unprecessable Entity)表明对象没有被实际写入。

如下所示,你可以继续上传其他分段:

  例 3.48. 上传大对象的下一个分段

PUT /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
ETag: 8a964ee2a5e88be344f36c22562a6486
Content-Length: 1
X-Object-Meta-PIN: 1234
w

接下来,在完成对象分段的上传后,你需要创建分段对象的清单,以指明分段对象所在的容器。请注意,在创建完清单后,如果你继续上传了该大对象的后续分段,会导致该大对象变得更大,但是你无需再为该后续分段创建一个新的清单。

  例 3.49. 上传清单

PUT /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
Content-Length: 0
X-Object-Meta-PIN: 1234
X-Object-Manifest: container/object/segments
[...]

针对清单的GET或HEAD请求的响应消息中的Content-Type与使用PUT请求创建清单时指定的Cotnent-Type相同。你可以再次使用PUT请求更改Content-Type。

3.4.2.2. 分块传输编码(Chunked Transfer Encoding)

用户可以在不知道上传的数据总量的情况下进行数据上传。为了实现这个目标,用户只需要用 Transfer-Encoding: chunked 请求头,且不使用 Content-Length 即可。执行数据库的dump操作就是一个使用该特性的很好的场景:使用管道对输出数据进行压缩,然后将压缩的数据直接上传到OpenStack对象存储中,而不需要在本地对数据进行缓存计算数据大小。如果用户尝试使用该方法上传大于5GB的对象时,服务器会在上传到5GB大小的数据时自动关闭TCP/IP连接,并将已经上传了的数据从系统中清除。因此,用户必须保证使用分块传输时你所上传的对象不能大于5GB,或将其分成小于5GB的分段对象再执行分块传输任务。如果你需要上传大于5GB的文件且仍然想使用对象存储时,你可以先将其进行分段上传到同一个容器中,再创建一个清单文件以保证可以将分段对象串联下载成一个单独的对象。

  例 3.50. 上传未指定数量的内容

PUT /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
Transfer-Encoding: chunked
X-Object-Meta-PIN: 1234
19
A bunch of data broken up
D
into chunks.
0

3.4.3. 为请求分配CORS头(Assigning CORS Headers to Requests)

CORS为一个定义,代表跨域资源共享(Cross-Origin Resource Sharing)。它定义了浏览器和服务器之间如何在不同源之间使用HTTP头进行交互,例如那些被Cloud Files API(YUKI注:这里应该是OpenStack Object Storage API吧)分配的请求。Cloud Files API支持这些headers。你可以在 www.w3.org/TR/access-control/ 上查看关于Access-Control- 响应头和源响应头的更多信息。

  • Access-Control-Allow-Credentials
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Origin
  • Access-Control-Expose-Headers
  • Access-Control-Max-Age
  • Access-Control-Request-Headers
  • Access-Control-Request-Method
  • Origin

这些头信息只可以被分配给objects使用。

  例 3.51. 分配CORS头

  在这个例子中,origin header的分配表明这个文件是从哪儿来的。这允许你对swift提供安全保证,以确保所存储的文件确实是从正确的源地址而来。

PUT /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
Origin: http://storage.clouddrive.com

3.4.4. 通过Content-Encoding头启用文件压缩

Content-Encoding 头允许对文件进行压缩而不丢失文件本身的多媒体类型,例如,一个视频。

  例 3.52. 使用Content-Encoding头的范例

  在这个例子中,Content-Encoding头被分配为一个附件类型,指明该文件的下载方式:

PUT /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
Content-Type: video/mp4
Content-Encoding: gzip

3.4.5. 通过Content-Disposition头启用浏览器旁路

当一个对象被分配了 Content-Disposition 头时,你可以覆盖一个浏览器针对文件的默认动作,从而实现使用下载器对文件进行下载,而非浏览器默认的展示文件的动作。

  例 3.53. 使用Content-Disposition头的范例

  在这个例子中,Content-Dispositon(原文此处有误)头被分配为一个附件类型,指明该文件的下载方式:

PUT /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
Content-Type: image/tiff
Content-Disposition: attachment; filename=platmap.tif

3.4.6. 通过X-Delete-After和X-Delete-At头使对象过期

当对一个对象执行PUT或POST操作,并对其分配了 X-Delete-AfterX-Delete-At 头时,这个对象就会在一定时间后被删除。这个特性对于存储非持久保留的数据是非常有用的,例如日志文件的存储(减少备份量)、在一定时间后会过期的图片文件或文档等。

X-Delete-At 的值必须为一个整数形式的Unix Epoch时间戳。例如,1348691905代表Wed, 26 Sep 2012 20:38:25 GMT。通过使用这个头信息设置一个特定的时间,你可以指明这个对象什么时候会过期,一旦超过这个时间,该对象就会从存储系统中完全删除。

X-Delete-After 的值为一个整数,指定多少秒后这个对象会被删除。当Proxy Server收到这个请求时,它会把X-Delete-After的值T取出,使用当前时间加上T计算出X-Delete-At的值,并将X-Delete-After转换为X-Delete-At。

如果你想对已经存在的对象使用这两个头信息,则只需要对其执行POST操作进行元数据的更新即可。

  例 3.54. Delete At的范例

  在这个例子中,X-Delete-At头的值为Unix纪元时间戳Mon, 11 Jun 2012 15:38:25 GMT的整数形式。请查看 http://www.epochconverter.com/ 查看时间戳范例和获取批量转换器。

PUT /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
Content-Type: image/jpeg
X-Delete-At: 1339429105

  例 3.55. Delete After的范例

  在这个例子中,X-Delete-After头的值为等于10天的秒数。在这个时间之后,这个对象就应该过期了。

PUT /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
Content-Type: image/jpeg
X-Delete-After: 864000

3.4.7. 对象版本管理(Object Versioning)

对象版本管理允许你对同一个对象的内容存储多个版本,以便在意外覆盖时实现对象内容的恢复。它提供了一种非常简单的方法来实现版本控制,而且可以用于任何类型的内容。我们强烈建议你将非当前版本的对象和当前版本的对象放在不同的容器中,一旦你启用了一个容器的Object Versioning(例如一个“当前版本”容器),使用PUT操作将这个容器中的对象复制到另一个“非当前版本”的容器中。每一个非当前版本的对象都附加有一个时间戳,因此你可以知道这个对象是什么时候创建的。

为了启用Object Versioning,你的存储提供商需要将容器配置文件中的 allow_versions 参数设置为TRUE。然后创建一个container,将非当前版本的对象写入。接下来,设置当前版本容器的元数据头X-Versions-Location,并将其指向你创建的非当前版本容器,非当前版本容器就是非当前版本的对象的存储位置。一旦这些工作完成了,每一个存储在你当前版本容器中的对象就启用了Object Versioning,对这些对象进行更改时,swift将会自动的在非当前版本容器中创建一个对应的非当前本对象。

当一个对象第一次被PUT到当前版本容器中时,非当前版本容器中将什么都不会写入。只有当你使用PUT请求对这些对象进行编辑时,才会在非当前本中创建对象。这些非当前版本对象使用以下schema进行标记:

Naming schema:非当前版本对象的命名规则为 <length><object_name>/<timestamp>。其中,<length> 为3个字符的零填充的<object_name>的十六进制字符长度,<timestamp>是这个非当前版本对象的创建时间。

任何一个形如2XX的返回码,如202(Accepted)都表明操作时成功的。4XX或5XX的状态码都意味着操作的失败。当你收到一个错误时,应当重试你的请求。请注意,如果你指定的容器并不存在一个对应的非当前版本container,且你编辑了当前版本的对象,则会返回一个状态码为412(Precondition Failed)的响应。如果你收到了这个错误,请检查这个container是否存在。

对versioned object执行GET请求,将会返回当前版本的对象,且不会执行任何请求重定向或元数据查询;

对versioned object执行POST请求,只会更新对象的元数据。此时,不会创建一个新版本的对象。换句话说,新版本的对象只在对象的内容被更改时才会创建;

对versioned object执行DELETE请求,将会删除当前版本的对象,并从非当前版本容器中移动下一个最新版本的对象到当前版本容器,用于替换被删掉的当前版本对象。这个“下一个最新”版本的对象会将它所有的元数据信息一起移动到当前版本中。如果你希望完全删除掉一个对象,且如果这个对象一共有5个版本,则你必须执行5次删除操作才能实现。

注意:

一个大对象的清单文件是不可以进行版本管理的,但是它可以指向versioned segments。
如果需要关闭当前本容器的版本管理功能,则只需要通过发送一个包含值为空的X-Versions-Location元数据头,删除该容器的X-Versions-Location元数据即可。

  例 3.56. 使用cURL进行对象版本管理

  首先确保具有版本存储的container存在,若没有创建一个(在本例中,我们称之为“versions”)。然后,使用X-Versions-Location头创建一个容器,在本例中我们称之为“current”。你可以为一个已存在的容器添加X-Versions-Location元数据来实现相同的目的。

  创建一个名为versions的容器:

curl -i -XPUT -H "X-Auth-Token: <token>" http://<storage_url>/versions

  使用X-Versions-Location头创建一个名为current的容器,并将其指向versions。

curl -i -XPUT -H "X-Auth-Token: <token>"-H "X-Versions-Location: versions" http://<storage_url>/current

  创建一个对象(第一个版本):

curl -i -XPUT --data-binary 1 -H "X-Auth-Token: <token>" http://<storage_url>/current/myobject

  现在,创建这个对象的一个新版本:

curl -i -XPUT --data-binary 2 -H "X-Auth-Token: <token>" http://<storage_url>/current/myobject

  查看这个对象较老版本的列表:

curl -i -H "X-Auth-Token: <token>" http://<storage_url>/versions?prefix=008myobject/

  现在,删除对象的当前版本,我们可以看到较老的版本也没有了(移动到current中了):

curl -i -XDELETE -H "X-Auth-Token: <token>" http://<storage_url>/current/myobject
curl -i -H "X-Auth-Token: <token>" http://<storage_url>/versions?prefix=008myobject/

3.4.8. 复制对象

假设,你使用错误的对象名或content-type上传了一个文件,或者你需要移动一些对象到另外一个容器中。如果没有一个服务器端的复制特性的话,你需要重复上传相同的内容、删除已经存在的对象来实现这些目的。如有使用了服务端的对象复制机制,那么你就可以省去重复上传内容的步骤,同时也可以节约带宽。

在swift中,有两种实现复制对象的方法。

第一种方法是对新对象(target)地址执行PUT操作,并添加 X-Copy-From 头指明数据的来源。这个头的值应该是源对象的容器名和对象名,并以“/container/object”的形式组合。此外,X-Copy-From PUT请求还需要一个Content-Length 头,即时它的值为0。

PUT /<api version>/<account>/<container>/<destobject> HTTP/1.1
Host: <storage URL>
X-Auth-Token: <some-auth-token>
X-Copy-From: /<container>/<sourceobject>
Content-Length: 0

第二种复制对象的方法也很类似。对一个存在的对象执行COPY操作,并且包含头 Destination 指明需要复制到的目标地址(target)。这个头的值为新对象的容器名和对象名以“/container/object”的形式构成的。

COPY /<api version>/<account>/<container>/<sourceobject> HTTP/1.1
Host: <storage URL>
X-Auth-Token: <some-auth-token>
Destination: /<container>/<destobject>

在这两种方法中,都需要保证目标容器在复制前就已经创建了。

如果你想移动一个对象而非复制它,你需要对老的对象执行DELETE操作。一个移动操作就是简单的COPY + DELETE的组合。所有的元数据在复制的过程中都会被保留。请注意,你可以在复制请求(PUT或COPY)中设置任何元数据,这个新设置的元数据如果和老的元数据有冲突,将会覆盖老的元数据。一个有趣的使用场景是,你可以将一个对象复制到它自己所在的位置,同时设置content-type为一个新的值,这是唯一可以改变一个已经存在对象的类型的方法。

3.4.9. 删除对象

对一个对象执行DELETE操作会将这个对象从系统中永久删除(包括元数据和数据)。

删除操作会在请求的时候立刻执行。任何对该被删除对象执行的GET, HEAD, POST或DELETE操作都会返回一个404(Not Found)错误。

包含元数据 X-Delete-AtX-Delete-After 的对象会在过期后的一天内被删除,而非一过期就被立刻删除。请参阅 3.4.6 查看更详细的信息。

  例 3.57. 删除对象的请求

DELETE /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb

一个没有内容的响应消息将会被返回。状态码204(No Content)表明对象已经被成功删除了;状态码404(Not Found)表明该对象不存在。

  例 3.58. 删除对象的响应

HTTP/1.1 204 No Content
Date: Thu, 07 Jun 2010 20:59:39 GMT
Server: Apache
Content-Type: text/plain; charset=UTF-8

3.4.10. 获取对象元数据

在对象执行HEAD操作可以获取该对象的元数据和其他标准 HTTP headers。

在这个请求中唯一需要谁知的头信息就是认证token。

  例 3.59. 获取对象元数据的请求

HEAD /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb

一个没有内容的响应消息将会被返回,元数据会以HTTP headers的形式返回。状态码200(OK)表明执行成功;状态码404(Not Found)表明该对象不存在。

你也许发现了object的HEAD响应内容格式与container的HEAD响应内容的格式不太一样。对象的HEAD响应消息不包含消息体,因此任何2xx格式的状态码都表明执行成功。当对container执行HEAD请求时,它将会查询container的数据库,但不会返回数据库内容,而返回204(No Content)。然而,当对object执行HEAD请求时,它则会返回200(OK),这是因为它可以查询到内容(元数据始终都是有的)。换句话说,对象的HEAD查询有一个容器的长度,而容器的HEAD查询只有0内容长度。

  例 3.60. 获取对象元数据的响应

HTTP/1.1 200 OK
Date: Thu, 07 Jun 2010 20:59:39 GMT
Server: Apache
Last-Modified: Fri, 12 Jun 2010 13:40:18 GMT
ETag: 8a964ee2a5e88be344f36c22562a6486
Content-Length: 512000
Content-Type: text/plain; charset=UTF-8
X-Object-Meta-Meat: Bacon
X-Object-Meta-Fruit: Bacon
X-Object-Meta-Veggie: Bacon
X-Object-Meta-Dairy: Bacon

3.4.11. 更新对象元数据

对object执行POST操作用于设置、重写相同key/value的元数据,或分配没有被分配的头信息,如用于设置对象过期的 X-Delete-At 和 X-Delete-After。你不可以使用POST请求来改变对象的其他头信息,例如 Content-TypeETag 等。POST不用于上传存储对象(PUT用于上传)。你也可以参考3.4.8.,在对象复制的时候更新元数据或其他头信息,例如Content-Type或CORS headers。

键的名称必须以X-Object-Meta-作为前缀。一个POST请求将会删除所有之前PUT/POST请求添加的元数据。

  例 3.61. 更新对象元数据的请求

POST /<api version>/<account>/<container>/<object> HTTP/1.1
Host: storage.swiftdrive.com
X-Auth-Token: eaaafd18-0fed-4b3a-81b4-663c99ec1cbb
X-Object-Meta-Fruit: Apple
X-Object-Meta-Veggie: Carrot

一个没有内容的响应消息将会被返回。状态码202(Accepted)表明执行成功;状态码404(Not Found)表明该对象不存在。

  例 3.61. 更新对象元数据的响应

HTTP/1.1 202 Accepted
Date: Thu, 07 Jun 2010 20:59:39 GMT
Server: Apache
Content-Length: 0
Content-Type: text/plain; charset=UTF-8

这节好多,好饿,咕~~(╯﹏╰)b 滚去吃饭了。。