京东云存储是京东提供的一款基于互联网的云存储服务,此服务让所有开发人员都能访问同一个具备高扩展性、可靠性、安全性和性价比的基础设施,而京东正是使用此种基础设施来运行其全球的网站网络的。该服务旨让扩展带来的优势得以最大化,并将这种优势传递给开发人员。
AccessKey与SecretKey是用户访问京东云存储API的身份标识,用户在使用京东云存储之前,应该向京东云鼎平台申请AccessKey与SecretKey并获得使用权限。具体信息请参考www.jcloud.com.
Bucket是存放“文件”(云存储称之为Object,)的容器,所有的Object都必须存放到某个Bucket中。
例如,你有个key为public/index.html的Object,存放到名字为“mybucket“的Bucket中,那么访问该Object的URI应该为:
http://storage.jcloud.com/mybucket/public/index.html
每个用户最多可以创建 100个Bucket,每个 Bucket 中可以存放无限多个 Object。Bucket 不能嵌套,每个 Bucket 中只能存放 Object,不能再存放 Bucket。
Bucket 的数量对云存储的性能没有影响,10 万个 Object 存放在同一个 Bucket 中和分布在 100 个不同的 Bucket 中的性能是一样的。
Bucket 的操作是中心化的,所以应尽量避免进行频繁的创建、删除 Bucket 等相关操作,推荐的方式是通过云存储控制台,或者只在应用程序初始化时进行创建,删除 Bucket 等相关的操作。
Bucket 的名称全局唯一且严格的限制,包括:
1. 仅包含小写英文字母(a-z),数字,点(.)和横线(-)
2. 必须由字母或数字开头和结尾
3. 长度在 3 和 63 个字符之间
4. 不能为IP地址形式,比如192.168.1.1
5. 不能包含连续的点(.)与横线(-)组合
为了发挥云存储的最大功能,我们强烈建议Bucket的名字符合域名规范,比如:music.jd.com, ump.jd.com, 非域名格式的bucket无法享受某些服务。
Object 是京东云存储中的基本实体,由键(Key),数据(Data)和元数据(Metadata)三部分组成。关于数据(Data),京东云存储并不关心其内容具体是什么。而元数据(Metadata)则是一组键值(Key-Value)的组合,分为系统预定义元数据(System-Defined Metadata)和用户自定义元数据(User-Defined Metadata)两部分。
注:用户自定义元数据(User-Defined Metadata) 将在未来开放其功能。
为了系统内部管理的需要,京东云存储对其存储的每一个的 Object 都维护一组系统定义元数据,包括数据的长度,创建时间,MD5 值等。
1. 使用 PUT Object 接口上传数据,数据长度限制为5GB。
Key 是一个 Object 的标识,在每一个Bucket 中,每个 Object 有且仅有一个 Key。而用户可以通过 Bucket + Key 的方式唯一标识云存储中的一个 Object,例如对于 URL:http://storage.jcloud.com/mybucket/public/index.html域名之后到第一个斜线(/)是 Bucket,为 mybucket,之后是 Object 的 Key,为public/index.html。
Key 为 UTF-8 编码,且符合如下规则
Key不能以”/”开头。
Key只能包含字母、数字、中文、”/”、”.”、”-”、”_” 组成。
Key的长度在1个字符到100个字符之间。
京东云存储会对访问的请求进行安全认证,只有通过认证的请求,才能访问云存储中的数据。
下面是认证的过程:
1. 客户端构造访问云存储的请求
2. 通过 SecretKey 计算请求的签名(Signature)
3. 将附带 AccessKey和签名(Signature)信息的请求发送给京东云存储系统
4. 京东云存储通过请求中的 AccessKey查找对应的 SecretKey
5. 京东云存储利用 SecretKey 重新计算请求的签名(Signature)
6. 若京东云存储计算的签名与客户端提供的签名相匹配,则认证通过,请求被接受,否则京东云存储拒绝处理该请求
京东云存储通过基于 Hmac(Hash Message Authentication Code)算法的自定义 HTTP 头来进行认证操作。要认证一个请求,客户端首先从请求中选取一些关键的元素组成一个字符串(String),然后利用自己的 SecretKey 计算该字符串的 Hmac 值,这个过程被称之为请求签名(signing the request),计算得出的 Hmac 值被称之为签名(signature),之后,用户将该签名以请求参数的形式发送给京东云存储。
带有认证信息的请求样例:
DELETE /ccd35eea-3c86-48f4-bd03-2acd5439d12f
Date: Tue, 21 May 2013 10:06:05 GMT
Authorization: jingdong9c379f079214447fad2959c4621cd6feVb797oH1:VREwI/vvZfgds1ueMjy6K0wfqjg=
Host: storage.jcloud.com
京东云存储 REST API通过标准的 HTTP 头 Authorization 来传递认证信息,下面是供参考的 HTTP 认证头模板:
Authorization: jingdong AccessKey:Signature
下面是生成 Authorization 头的伪代码:
Authorization ="jingdong" + " " + AccessKey + ":" + Signature;
Signature =Base64( HMAC-SHA1( YourSecretKey, UTF-8-Encoding-Of( StringToSign ) ) );
StringToSign =HTTP-Verb + "\n" +
Content-MD5 + "\n" +
Content-Type + "\n" +
Date + "\n" +
CanonicalizedHeaders +
CanonicalizedResource;
CanonicalizedResource= [ "/" + Bucket ] +
[ sub-resource, if present. For example"?acl", "?location", "?logging", or "?torrent"];
注意:目前京东云存储不支持CanonicalizedHeaders,因此其以空字符串(“”)代替。
当 Content-Type ,Content-MD5 不存在时,由空字符串代替。
HMAC-SHA1算法的详细信息可参看RFC2104(http://www.ietf.org/rfc/rfc2104.txt)标准。该算法输入两个参数:Key 和 Message,并计算出一个结果Digest。对于京东云存储来说,Key 就是 SecretKey,Message 就是 UTF-8 编码的 StringToSign,计算出的结果 Digest 经过Base64编码之后就是 Signature。
CanonicalizedResource代表了请求的目标资源,构造过程如下:
1. 以空字符串开头(“”)。
2. 加上Bucket 的名称。
3. 加上未解码(un-decoded)的 HTTP 请求 URI,截止到查询字符串(query string)之前。
4. 若请求的资源类型是子资源(sub-resource),则加上子资源的名称。这些子资源包括:lifecycle,location,logging,partNumber,policy,uploadId,uploads,versionId,versioning,versions,website 等。
每一个认证的请求都必须包含一个有效的时间戳,HTTP Header”Date”或者”x-jd-date”。客户端提供的时间戳和京东云存储服务器的本地时间相差不得超过 15分钟,否则服务器会拒绝该请求,且返回 RequestTimeTooSkewed 错误。通过这种方式可以有效防止请求重放,盗链等恶意攻击。
一些HTTP Client库并不提供显式设置HTTPHeader”Date”的方式,如果此时不能准确的组合StringToSign中Date 的值,可以通过设置 Http Header”x-jd-date”的方式来取代 HTTP Header”Date”,其格式与Date相同,必须为 RFC 2616 格式中的一种(http://www.ietf.org/rfc/rfc2616.txt)。如果通过”x-jd-date”来代替”Date”提供时间戳,则在构造StringToSign 时,应忽略 Date 并以空字符串(““)代替。
4.2.7. 例子
下面的例子使用表格中的 AccessKey与SercetKey 进行 HMAC-SHA1 计算
AccessKey | SercetKey |
9c379f079214447fad2959c4621cd6feVb797oH1 | 5e998dbbafb44ca783099afcdead40fa7A3Vf7Fh |
Put Bucket请求
Request | StringToSign |
PUT /ab52b360-5370-4c03-906f-8b80e7e0c130 Date: Wed, 22 May 2013 02:05:58 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:5IGUVXmvjWCJfkRDH7G+/gyIsf8= | PUT \n \n Wed, 22 May 2013 02:05:58 GMT /ab52b360-5370-4c03-906f-8b80e7e0c130 |
Del Bucket 请求
Request | StringToSign |
DELETE /ab52b360-5370-4c03-906f-8b80e7e0c130 Date: Wed, 22 May 2013 02:05:58 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:vKCbKp/kKY/qKb4wNPqWywbh0qE= | DELETE \n \n Wed, 22 May 2013 02:05:58 GMT /ab52b360-5370-4c03-906f-8b80e7e0c130 |
Put Object
Request | StringToSign |
PUT /7d84df14-6e90-4101-bd92-0201966eacc5/24b1c9ba-c889-4a76-8edc-bd8fa7e417dc Content-MD5: 670f34c390bd3deb23c99999771064ad Content-Type: application/octet-stream Date: Wed, 22 May 2013 02:37:02 GMT Authorization:jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:J6yRNUPxjixPsJusHuHk0JNK1Lo= | PUT 670f34c390bd3deb23c99999771064ad application/oc tet-stream Wed, 22 May 2013 02:37:02 GMT /7d84df14-6e90-4101-bd92-0201966eacc5/24b1c9ba-c889-4a76-8edc-bd8fa7e417dc |
Get Object
Request | StringToSign |
GET /7d84df14-6e90-4101-bd92-0201966eacc5/24b1c9ba-c889-4a76-8edc-bd8fa7e417dc Date: Wed, 22 May 2013 02:37:02 GMT Authorization:jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:domGmvXwG2i3Vpri9+J12zLnMtI= | GET \n \n Wed, 22 May 2013 02:37:02 GMT /7d84df14-6e90-4101-bd92-0201966eacc5/24b1c9ba-c889-4a76-8edc-bd8fa7e417dc |
除了前面提到的认证方式之外,京东云存储还提供了一种基于查询字串(Query String)的认证方式,即通过查询字符串来指定 AccessKey,Signature 等信息来构造认证请求。这样的好处是可以使第三方用户,直接通过浏览器来访问你存储中未公开的数据。
具体办法是,通过预签名的方式,生成一个带有认证信息的 URL,并将它分发给第三方用户。通常,你需要为这个 URL 指定一个过期时间。
下面是一个基于查询字符串的认证的URI:
http://storage.jcloud.com/mybucket/public/index.html?Expires=1369191796&AccessKey=9c379f079214447fad2959c4621cd6feVb797oH1&Sigature=tzEQUA%2Bj%2BUHcEp%2FBUMKeMd5bqGc%3D
基于查询字符串的认证请求不需要任何特殊的 HTTP Header,它通过查询字符串来指定认证信息。
查询字符串参数 | 样例值 | 描述 |
AccessKey | 9c379f079214447fad2959c4621cd6feVb797oH1 | 你的AccessKey |
Expires | 1369191796 | URL 的过期时间,为距离 UTC 时区 1970 年 1 月 1 日 0 时的秒数,超过该时间的请 求都会被拒绝 |
Signature | tzEQUA%2Bj%2BUHcEp%2FBUMKeMd5bqGc%3D | 经过 URL-Encoding 编码之 后的 Signature |
构造基于查询字符串认证请求的签名与基于 HTTP Header 的传统方式有一些不同,可以参考下面的伪代码:
Signature =URL-Encode(Base64(HMAC-SHA1(UTF-8-Encoding-Of(YourSecretKey,
StringToSign))));
StringToSign =HTTP-Verb + "\n" +
Content-MD5 +"\n" +
Content-Type +"\n" +
Expires +"\n" +
CanonicalizedAHeaders+
CanonicalizedResource;
主要的不同有两点:
1. 需要对计算出来的签名进行 URL-Encode 编码
2. 将StringToSign 中的 Date 换成 Expires
下面的例子使用表格中的 AccessKey与SercetKey 进行 HMAC-SHA1 计算
AccessKey | SercetKey |
9c379f079214447fad2959c4621cd6feVb797oH1 | 5e998dbbafb44ca783099afcdead40fa7A3Vf7Fh |
GET Object 请求
Request | StringToSign |
GET /mybucket/public/index.html?Expires=1369191796414&AccessKey=9c379f079214447fad2959c4621cd6feVb797oH1&Sigature=tzEQUA%2Bj%2BUHcEp%2FBUMKeMd5bqGc%3D Host: storage.jcloud.com | GET \n \n 1369191796 /mybucket/public/index.html |
错误码 | Http状态码 | 描述 |
AccessDenied | 403 Forbidden | 访问被拒绝 |
AccountProblem | 403 Forbidden | 帐号被冻结,通常是流量超标或者其他原因引起 |
BadDigest | 400 Bad Request | 提供的 Content-MD5 值与服务端计算的不匹配 |
BucketAccessDenied | 403 Forbidden | 没有权限访问目标Bucket |
BucketAlreadyExists | 409 Conflict | 要创建的 Bucket 已 存在 ,Bucket 名称全局唯一,请重新选择 |
BucketNotEmpty | 409 Conflict | 要删除的 Bucket 不为空 |
EntityTooLarge | 400 Bad Request | 上传的数据大小超过了限制 |
IncompleteBody | 400 Bad Request | 上 传 的 数 据 大 小 小 于 HTTP Header 中的 Content-Length |
InvalidBucketName | 400 Bad Request | 要创建的 Bucket 名称不合法 |
KeyTooLong | 400 Bad Request | Object Key 长度过长 |
MissingContentLength | 411 Length Required | 缺少 HTTP Header Content-Length |
NoSuchBucket | 404 Not Found | 请求的 Bucket 不存在 |
NoSuchKey | 404 Not Found | 请求的 Object 不存在 |
TooManyBuckets | 400 Bad Request | 要创建的 Bucket 数目超过了极限 |
RequestTimeTooSkewed | 403 Forbidden | 请求的时间戳与服务器本地时间差距过大,被拒绝 |
InvalidPart | 400 Bad Request | Complete Multipart Upload 时,HTTP请求中的Part在云存储中找不到,可能这些Part没有被上传 |
InvalidEntity | 400 Bad Request | HTTP请求的Entity无效 |
InvalidPartNumber | 400 Bad Request | Complete Multipart Upload 时,HTTP请求中的Partnumber在规定范围外 |
在与 API 交互有错误发生时,云存储服务端的响应(Response)包括:
1. 相应的 HTTP 3xx,4xx 与 5xx 状态码(HTTP Status)
2. XML或JSON格式的消息体
下面是XML样例
AccessDenied
下面是JSON样例
{“code” :”AccessDenied”,”message”:”Access Denied”,”resource”:”/mybucket/public/index.html”,”requestId”:”71515159-E06D-406F-81C4-E03FA635B831”}
服务端返回JSON或者XML取决于客户端HttpRequest Header的Accept的值,如果希望返回XML,请设置Accept的值为:application/xml 否则默认返回JSON。
下面的表格中介绍了每一个元素(Element)的意义:
名称 | 描述 |
code | 错误代码 |
message | 错误消息的描述,可以通过此信息来初步定位问题所在。 |
RequestId | 标识请求的唯一 ID。 |
Resource | 包含了 Bucket 或 Object 的请求资源描述符。 |
下面的表格是访问京东云存储 API 的通用请求头(HTTP Headers):
名称 | 描述 | 必须 |
Authorization | 请求的验证信息 | 是 |
Content-Length | 消息体的长度,PUT 请求必要。 | 部分 |
Content-Type | 资源的类型,例如:text/plain。 | 否 |
Date | 请求的时间戳,例如:Mon, 23 Feb 2013 03:14:57 GMT。 | 是 |
Host | 值应该是storage.jcloud.com,HTTP/1.1 协议必要,HTTP/1.0 协议选填。 | 部分 |
下面的表格是京东云存储 API 的返回的通用响应头(HTTP Headers)
名称 | 描述 |
Content-Length | 响应消息体长度 |
Connection | 标识 HTTP Connection 的状态,Open 或者 Closed |
Date | 云存储服务器响应本次请求的时间戳,例如Wed, 22 May 2013 05:29:49 GMT |
ETag | ETag 是云存储中 Object 的 Hash 值,其仅反映 Object 的数据 内容,而不包括元数据(Metadata)。需要注意的是 ETag 不一定 是一个 MD5 值,当 PUT Object 操作完成时,服务端会为收到的 数据生成 MD5 摘要作为其 ETag。而对于 Multipart Upload 产 生的 Object, 其 ETag 并不是内容的 ContentMD5 |
x-jss-request-id | 本次请求的唯一标识。若有错误发生时,客户可将该 ID 告诉京东云存储来帮助定位问题 |
x-powered-by | 固定值为JingdongStorageService,表示该请求是由京东云存储完成 |
描述
可以通过该操作来列出客户所有的Bucket信息。
Requests:
Syntax
GET /HTTP/1.1 Host: storage.jcloud.com Date: date Authorization: signatureValue |
Response:
返回的header见5.2.2;初始化成功,返回的Body是json格式。详见example
Responseelements:
名称 | 描述 |
Bucket | Bucket的名称。 |
CreationDate | Bucket创建的时间戳。 |
Example:
Request:
GET / Date: Thu, 11 Jul 2013 10:29:09 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:T9catk8sYiAlEwHHm2aRV5WRpnQ= Host: storage.jcloud.com Connection: Keep-Alive User-Agent: JSS-SDK-JAVA/1.1.0 (Java 1.7.0_21; Vendor Oracle Corporation; Linux 3.5.0-17-generic; HttpClient 4.2.1) |
Response:
200 Server: nginx/1.2.7 Date: Thu, 11 Jul 2013 10:32:30 GMT Content-Type: application/json;charset=UTF-8 Content-Length: 1951 Connection: keep-alive
{"Buckets":[{"Name":"jwt.jcloud.com.jssbuket","CreationDate":"Thu, 20 Jun 2013 09:33:45 GMT","Location":"beijing"},{"Name":"jindong","CreationDate":"Thu, 20 Jun 2013 10:22:45 GMT","Location":"beijing"},{"Name":"code.jd.com","CreationDate":"Tue, 25 Jun 2013 06:25:45 GMT","Location":"beijing"},{"Name":"test866ad","CreationDate":"Tue, 25 Jun 2013 08:38:08 GMT","Location":"beijing"},{"Name":"zxq-test-bucket","CreationDate":"Tue, 25 Jun 2013 10:08:41 GMT","Location":"beijing"},{"Name":"storage-script","CreationDate":"Wed, 26 Jun 2013 07:42:37 GMT","Location":"beijing"},{"Name":"boss.jd.com","CreationDate":"Tue, 25 Jun 2013 06:49:44 GMT","Location":"beijing"},{"Name":"bucketname1","CreationDate":"Tue, 25 Jun 2013 06:39:27 GMT","Location":"beijing"},{"Name":"bucketname2","CreationDate":"Tue, 25 Jun 2013 06:43:35 GMT","Location":"beijing"},{"Name":"liningbo","CreationDate":"Tue, 25 Jun 2013 08:48:57 GMT","Location":"beijing"},{"Name":"dengliang","CreationDate":"Thu, 27 Jun 2013 03:00:24 GMT","Location":"beijing"},{"Name":"storage-pic-cast1","CreationDate":"Thu, 27 Jun 2013 12:49:11 GMT","Location":"beijing"},{"Name":"cloudtest-apk","CreationDate":"Fri, 28 Jun 2013 01:28:34 GMT","Location":"beijing"},{"Name":"sunyansd","CreationDate":"Mon, 01 Jul 2013 05:06:20 GMT","Location":"beijing"},{"Name":"jxqstu3","CreationDate":"Fri, 05 Jul 2013 02:13:16 GMT","Location":"beijing"},{"Name":"yangxuanjia.com.cn","CreationDate":"Fri, 05 Jul 2013 03:08:30 GMT","Location":"beijing"},{"Name":"dengliangtest","CreationDate":"Tue, 02 Jul 2013 07:47:45 GMT","Location":"beijing"},{"Name":"adf1","CreationDate":"Wed, 03 Jul 2013 02:32:17 GMT","Location":"beijing"},{"Name":"bucketname21","CreationDate":"Thu, 04 Jul 2013 03:44:33 GMT","Location":"beijing"},{"Name":"cloudtest-picture","CreationDate":"Sat, 06 Jul 2013 03:38:57 GMT","Location":"beijing"},{"Name":"cloudtest-normal-log","CreationDate":"Sat, 06 Jul 2013 03:38:58 GMT","Location":"beijing"}]} |
描述
该操作可以创建一个新的Bucket。
Request:
Syntax
PUT /BucketName HTTP/1.1 Host: storage.jcloud.com Date: date Authorization: signatureValue |
Response:
返回的header见5.2.2;返回body为空。
Example:
Request:
PUT /testbucket Date: Thu, 11 Jul 2013 11:57:38 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:wG7zP5ittOVhXEKemmEUK9tbVTg= Content-Length: 0 Host: storage.jcloud.com Connection: Keep-Alive User-Agent: JSS-SDK-JAVA/1.1.0 (Java 1.7.0_21; Vendor Oracle Corporation; Linux 3.5.0-17-generic; HttpClient 4.2.1) |
Response:
200 Server: nginx/1.2.7 Date: Thu, 11 Jul 2013 12:00:59 GMT Content-Length: 0 Connection: keep-alive |
描述
删除URI所指定的Bucket,删除该Bucket之前,必须确保该Bucket中没有任何数据。
Request:
Syntax
DELETE /BucketNameHTTP/1.1 Host: storage.jcloud.com Date:date Authorization: signatureValue |
Response:
返回的header见5.2.2;返回的Body为空。
Example:
Request:
DELETE /testbucket Date: Thu, 11 Jul 2013 12:08:08 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:atST2N3UyucwTw/YSaknYMBy5A4= Host: storage.jcloud.com Connection: Keep-Alive User-Agent: JSS-SDK-JAVA/1.1.0 (Java 1.7.0_21; Vendor Oracle Corporation; Linux 3.5.0-17-generic; HttpClient 4.2.1) |
Response:
204 Server: nginx/1.2.7 Date: Thu, 11 Jul 2013 12:11:30 GMT Connection: keep-alive |
描述
该操作可以获得指定Bucket中的Object信息列表,请求时可以通过一些查询条件来限制返回的结果。
Request:
Syntax
GET /BucketNameHTTP/1.1 Host: storage.jcloud.com Date: date Authorization: signatureValue |
Requestelement
名称 | 描述 | 必要 |
marker | 返回以字典序排序的Object信息的起始标志,结果中不包含marker,通常与max-keys一起使用来实现分页
|
|
max-keys | 返回Object信息的数量,最大为1000,若有更多符合查询条件的Object信息没有被返回,则响应中会包含HasNext为true元素,同时可以设定marker为本次列表最后一个Key,来获取其他的本次操作未返回的Object信息。默认为1000
|
|
prefix | 限制返回Object的Key的前缀 |
|
delimiter | 分组符,用于分组返回的Object的Key。当prefix未指定时,从Object的Key中提取第一个字符到第一个delimiter之间的字符串放在CommonPrefixes中返回。若指定了prefix,则提取prefix到第一个delimiter之间的字符串放在CommonPrefixes中返回。 |
|
Response:
返回的header见5.2.2;初始化成功,返回的Body是json格式。
Responseelements:
名称 | 描述 |
Name | Bucket的名称 |
Delimiter | 指定的Delimiter分组符 |
Prefix | 指定的Object Key的前缀 |
MaxKeys | 指定的Object的数量 |
Marker | 指定的Object的Key的起始标志 |
NextMarker | 列出下一个集合的Marker,只有当用户设置了delimiter 且 HasNext为true时才会出现,其值可能是当前集合中最后一个Key,或是CommonPrefixes中最后一个Prefix 若用户没有设置delimiter,且HasNext为true时,可以直接将返回集合中的最后一个Key作为列出下一个结合的Marker |
HasNext | 标识返回的结果是否完整(true or false),若符合条件的Object 信息数量超过了指定的MaxKeys,则该值为true,且多余的结果也不会被返回。 |
Contents | 包含了一个Object信息的容器 |
Key | Object的Key |
LastModified | Object的最后修改时间 |
ETag | Object的ETag是一个MD5 hash值,其只反映Object内容的变化,而不是元数据(Metadata) |
Size | Object的大小 |
CommonPrefixes | 用户指定了Delimiter时,该元素才会出现。用于存放分组后Object Key前缀。 |
Example:
Request:
GET /liningbo Date: Fri, 12 Jul 2013 02:49:47 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:WMlS9FnrrOz9MiWGq3D9LLxjLl0= Host: storage.jcloud.com Connection: Keep-Alive User-Agent: JSS-SDK-JAVA/1.1.0 (Java 1.7.0_21; Vendor Oracle Corporation; Linux 3.5.0-17-generic; HttpClient 4.2.1) |
Response:
200 Server: nginx/1.2.7 Date: Fri, 12 Jul 2013 02:53:09 GMT Content-Type: application/json;charset=UTF-8 Content-Length: 492 Connection: keep-alive
{"Name":"liningbo","Prefix":null,"Marker":null,"Delimiter":null,"MaxKeys":1000,"HasNext":false,"Contents":[{"Key":"hadoop1","LastModified":"Tue, 02 Jul 2013 06:11:12 GMT","ETag":"fdec55af07620fd5ecad717167d79a8c","Size":151080960},{"Key":"pid1","LastModified":"Fri, 12 Jul 2013 02:51:49 GMT","ETag":"ea88976b9952e80b702b030489f94393","Size":10069279},{"Key":"testObject","LastModified":"Tue, 02 Jul 2013 02:42:25 GMT","ETag":"d25ebb012cdbb28a3f309ea565c56cea","Size":82}],"CommonPrefixes":[]} |
描述
该操作用来上传一个新的Object到指定的Bucket中,数据的最大长度限制为5GB。更大的文件建议采取分块上传。
该操作为原子操作,即操作要么成功,要么失败,且不存在只更新部分数据的情况,在存在相当key的情况下,目前不支持覆盖操作。
客户端可以通过HTTP 头Content-MD5进行端到端验证来保证上传数据的完整性。在上传之前,客户端自己计算出上传数据的Content-MD5值,并将其与数据一起上传至云存储。云存储接收到数据之后,会重新计算收到数据的Content-MD5值,并与客户端提供的Content-MD5进行比对,只有在Content-MD5匹配的情况下,才会将数据保存至云存储,否则服务端会返回错误使上传操作失败。
Request:
Syntax
PUT /BucketName/ObjectNameHTTP/1.1 Host: storage.jcloud.com Date: date Authorization: signatureValue |
Response:
返回的header见5.2.2;初始化成功,返回的Body为空。
Example:
Request:
PUT /liningbo/pid1 Content-Type: application/octet-stream Content-MD5: ea88976b9952e80b702b030489f94393 Content-Disposition: attachment; filename="pidgin-2.10.7.tar.bz2" Date: Fri, 12 Jul 2013 02:20:16 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:YyqxZ9uR1HiRS5CMYN5Alf2vJZM= Content-Length: 10069279 Host: storage.jcloud.com Connection: Keep-Alive User-Agent: JSS-SDK-JAVA/1.1.0 (Java 1.7.0_21; Vendor Oracle Corporation; Linux 3.5.0-17-generic; HttpClient 4.2.1)
文件内容 |
Response:
200 Server: nginx/1.2.7 Date: Fri, 12 Jul 2013 02:23:42 GMT Content-Length: 0 Connection: keep-alive |
描述
获取指定的Object内容。
Request:
Syntax
GET /BucketName/ObjectNameHTTP/1.1 Host: storage.jcloud.com Date: date Authorization: signatureValue Range:bytes=byte_range |
Requestheader
见5.2.1节,Range是指定获取的Object数据内容。更多的信息可以参看:http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
Response:
返回的header见5.2.2;初始化成功,返回的Body是实际的对象内容。
Example:
Request:
GET /liningbo/pid1 Date: Fri, 12 Jul 2013 02:28:41 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:ud+zLHgqpaYmQzg6j7teZUTsLUg= Host: storage.jcloud.com Connection: Keep-Alive User-Agent: JSS-SDK-JAVA/1.1.0 (Java 1.7.0_21; Vendor Oracle Corporation; Linux 3.5.0-17-generic; HttpClient 4.2.1) |
Response:
200 Server: nginx/1.2.7 Date: Fri, 12 Jul 2013 02:32:03 GMT Content-Type: application/octet-stream Content-Length: 10069279 Connection: keep-alive ETag: "ea88976b9952e80b702b030489f94393" Last-Modified: Fri, 12 Jul 2013 02:22:39 GMT Content-Disposition: attachment; filename="pid1" Accept-Ranges: bytes
文件内容 |
描述
删除URI所指定的Object。
Request:
Syntax
GET /BucketName/ObjectNameHTTP/1.1 Host: storage.jcloud.com Date: date Authorization: signatureValue Range:bytes=byte_range |
Response:
返回的header见5.2.2;初始化成功,返回的Body为空。
Example:
Request:
DELETE /liningbo/pid1 Date: Fri, 12 Jul 2013 02:33:06 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:uDyHrsK2+9p5INuaQA1rKjwFjlY= Host: storage.jcloud.com Connection: Keep-Alive User-Agent: JSS-SDK-JAVA/1.1.0 (Java 1.7.0_21; Vendor Oracle Corporation; Linux 3.5.0-17-generic; HttpClient 4.2.1) |
Response:
204 Server: nginx/1.2.7 Date: Fri, 12 Jul 2013 02:36:28 GMT Connection: keep-alive |
描述
该操初始化一个新的Multipart Upload,成功后返回一个UploadId。用户通过该UploadId来进行Multipart Upload相关的操作,包括上传Multipart Upload所属的Part,合并所有Part,终止Multipart Upload,列出已上传的Part等。
Requests:
Syntax
POST /BucketName/ObjectName?uploads HTTP/1.1 Host: storage.jcloud.com Date: date Authorization: signatureValue |
Response:
返回的header见5.2.2;初始化成功,返回的Body是json格式。
Response element
Name | Description |
Bucket | 桶名。Type: string |
Key | 对象名。Type: String |
UploadId | 本次分块上传的ID。Type: String |
Examples
SampleRequest
POST /liningbo/testObject?uploads Date: Mon, 01 Jul 2013 09:13:50 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:dY2ZqYyTiXOVQl4fZ4iaXW6UybA= Content-Length: 0 Host: storage.jcloud.com Connection: Keep-Alive User-Agent: JSS-SDK-JAVA/1.1.0 (Java 1.7.0_21; Vendor Oracle Corporation; Linux 3.5.0-17-generic; HttpClient 4.2.1) |
SampleResponse
200 Server: nginx/1.2.7 Date: Mon, 01 Jul 2013 09:16:47 GMT Content-Type: application/json;charset=UTF-8 Content-Length: 86 Connection: close
{"Bucket":"liningbo","Key":"testObject","UploadId":"1e34f32a9d1c40ccab504b3c39074dcc"} |
描述
该操作用来上传一个的Part到指定的Multipart Upload中。
在上传Part之前,必须先完成Initiate Multipart Upload操作,操作完成后会得到标识符Upload Id,该标识符唯一标识一个Multipart Upload。在上传Part时应指定其关联事件的Upload Id。
Part Number的范围在1-10000之间,Part Number唯一标识一个Part和其所在MultipartUpload中的位置。如果你Upload Part时,用了同一个Part Number,服务端会直接返回上传成功,不会替换原来的Part。建议分块大小不小于5M。
为了保证数据的传输的正确性,服务端会在Part上传成功后返回实际存储的Part的MD5值,放在响应的header的ETag字段中,用于客户端校验。
Requests:
Syntax
PUT /BucketName/ObjectName?partNumber=PartNumber&uploadId=UploadIdHTTP/1.1 Host: storage.jcloud.com Date: date Content-Length: Size Authorization: signatureValue |
Requestelements
名称 | 描述 | 必要 |
Content-Length | 要上传的数据内容长度,长度范围在0到5GB之间 | 是 |
Content-MD5 | 期待上传数据的MD5值,其内容为Object内容(不包含Headers)的16进制编码的128位MD5摘要 | 否 |
Response:
返回的header见5.2.2,ETag是本次上传的MD5值,16进制表示;上传成功,返回的Body为空。详见example
Examples
SampleRequest
PUT /liningbo/testObject?partNumber=1&uploadId=1e34f32a9d1c40ccab504b3c39074dcc Date: Mon, 01 Jul 2013 09:21:30 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:TyozaAoj0oqsbV0TvUjmtmkyKPk= Content-Length: 30 Host: storage.jcloud.com Connection: Keep-Alive User-Agent: JSS-SDK-JAVA/1.1.0 (Java 1.7.0_21; Vendor Oracle Corporation; Linux 3.5.0-17-generic; HttpClient 4.2.1)
文件内容 |
SampleResponse
200 Server: nginx/1.2.7 Date: Mon, 01 Jul 2013 09:24:27 GMT Content-Length: 0 Connection: close ETag: "a46857f0ecc21f0a06ea434b94d9cf1d" |
描述
该操作用来完成Multipart Upload,合并其包含的所有Part,并在云存储中产生一个新的Object。
当用户初始化Multipart Upload并上传了所有相关的Part之后,你可以通过该操作完成整个Multipart Upload。收到该请求后,云存储根据每一个Part Number的顺序,将已经上传的所有的Part合并成一个Object。你必须保证你提供了完整有效的Part列表:所有的Part按照PartNumber升序排列,不能有无法识别的Part,不能有遗漏的Part。目前,客户端与服务端在http body中以json格式交互。
Requests:
Syntax
POST /BucketName/ObjectName?uploadId=UploadIdHTTP/1.1 Host: storage.jcloud.com Date: Date Content-Length: Size Authorization: signatureValue {"Part":[{"PartNumber":PartNumberValue,"ETag":"ETagValue"},{"PartNumber":PartNumberValue,"ETag":"ETagValue"}]} |
request element:
Name | Description |
Bucket | 桶名。Type: string |
Key | 对象名。Type: String |
ETag | 整块文件的MD5值,16进制表示。Type: String |
Response:
Response header见5.2.2节,responsebody是json字符串,其中的ETag字段是合并后整个文件的MD5值,用16进制表示,详见example
Example:
SampleRequest
POST /liningbo/testObject?uploadId=1e34f32a9d1c40ccab504b3c39074dcc Date: Tue, 02 Jul 2013 02:40:33 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:VTOKgwBVTB63XYfDC0WtbRBl6a0= Content-Length: 128 Host: storage.jcloud.com Connection: Keep-Alive User-Agent: JSS-SDK-JAVA/1.1.0 (Java 1.7.0_21; Vendor Oracle Corporation; Linux 3.5.0-17-generic; HttpClient 4.2.1)
{"Part":[{"PartNumber":1,"ETag":"a54357aff0632cce46d942af68356b38"},{"PartNumber":2,"ETag":"0c78aef83f66abc1fa1e8477f296d394"}]} |
SampleResponse
200 Server: nginx/1.2.7 Date: Tue, 02 Jul 2013 02:43:30 GMT Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Connection: close
{"Bucket":"liningbo","Key":"testObject","ETag":"d25ebb012cdbb28a3f309ea565c56cea"} |
描述
该操作用来终止一个Multipart Upload。当一个Multipart Upload被终止后,其UploadId也一同作废,且该Multipart Upload中的所有Part所占用的存储空间都会被释放。
Requests:
Syntax
DELETE /BucketName/ObjectName?uploadId=UploadIdHTTP/1.1 Host:storage.jcloud.com Date: Date Authorization: signatureValue |
Responses
Response Headers
见5.2.2
Response body:
空.
Example:
SampleRequest
DELETE /liningbo/myObject?uploadId=129a345df24d46ffb1c111cb6c375f80 Date: Tue, 02 Jul 2013 02:45:20 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:EyXc7mzCkF5OGk7GM73IZnxgJ6M= Host: storage.jcloud.com Connection: Keep-Alive User-Agent: JSS-SDK-JAVA/1.1.0 (Java 1.7.0_21; Vendor Oracle Corporation; Linux 3.5.0-17-generic; HttpClient 4.2.1) |
SampleResponse
204 Server: nginx/1.2.7 Date: Tue, 02 Jul 2013 02:48:16 GMT Connection: close |
描述
该操作用来列出一个Multipart Upload中已经上传的Part。
该操作必须指定UploadId,返回的Part数量最大为1000。你可以通过设置查询字符串参数max-parts来限定返回Part的数量,默认为1000。若符合条件的结果超过1000,Response结构中的会包含NextPartNumberMarker元素以及值为true的HasNext元素。此时你可以通过设置查询字符串参数part-number-marker为NextPartNumberMarker来列出下一个Part集合。
Requests:
Syntax
GET /BucketName/ObjectName?uploadId=UploadIdHTTP/1.1 Host:storage.jcloud.com Date: Date Authorization: signatureValue |
Request elements
名称 | 描述 | 必要 |
uploadId | Multipart Upload的Id | 是 |
max-parts | 返回Part的数量
| 否 |
part-number-marker | 返回Part的起始标志,只有PartNumber大于该参数的Part才会被返回 | 否 |
Responses
Response Headers
见5.2.2
Response Body
Json格式的字符串,详见example
Response Elements
Name | Description |
Bucket | 桶名。Type: string |
Key | 对象名,即Object的Key 。Type: String |
UploadId | Multipart Upload的Id 。Type: String |
PartNumberMarker | 返回Part的起始标志。Type: Integer |
NextPartNumberMarker | 当HasNext为true时,返回的结果会包含该值,此时可以通过设置查询字符串参数part-number-marker为该值来列出下一个Part集合。Type: Integer |
MaxParts | 返回Part的数量,最大为1000,默认为1000 。Type: Integer |
HasNext | 标识返回的结果是否完整(true or false),若符合条件的Part数目超过了指定的MaxParts,则该值为True,且多余的结果也不会被返回。Type: bool |
Part | 包含了一个 Part信息的容器。Type: String |
PartNumber | Part的标识。Type: Date |
LastModified | Part的上传时间。Type: Date |
ETag | Part的ETag 。Type: String |
Size | Part内容的长度。Type: Integer |
Example:
Sample Request
GET /liningbo/testObject?uploadId=1e34f32a9d1c40ccab504b3c39074dcc Date: Mon, 01 Jul 2013 09:39:46 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:atYBHOsWYBSz0cpbMpUYsSmorYs= Host: storage.jcloud.com Connection: Keep-Alive User-Agent: JSS-SDK-JAVA/1.1.0 (Java 1.7.0_21; Vendor Oracle Corporation; Linux 3.5.0-17-generic; HttpClient 4.2.1) |
SampleResponse
200 Server: nginx/1.2.7 Date: Mon, 01 Jul 2013 09:42:42 GMT Content-Type: application/json;charset=UTF-8 Content-Length: 407 Connection: close
{"Bucket":"liningbo","Key":"testObject","UploadId":"1e34f32a9d1c40ccab504b3c39074dcc","PartNumberMarker":0,"NextPartNumberMarker":null,"MaxParts":1000,"HasNext":false,"Part":[{"PartNumber":1,"LastModified":"Mon, 01 Jul 2013 09:24:27 GMT","ETag":"a46857f0ecc21f0a06ea434b94d9cf1d","Size":30},{"PartNumber":2,"LastModified":"Mon, 01 Jul 2013 09:25:43 GMT","ETag":"55032b1ba8bc84b3755818c8a48ea031","Size":52}]} |
描述
该操作可以列出还未完成的MultipartUpload,请求时可以通过一些查询条件来限制返回的结果。
该操作最多返回1000个Multipart Upload。你也可以通过设置查询字符串参数max-uploads来限制返回Multipart Upload的数量,如果符合查询条件的结果超过1000个,则返回Response的结构中HasNext元素值为true,此时可以通过设置查询字符串参数key-marker和upload-id-marker来获取更多的Multipart Upload。
返回的结果按照Key和UploadId的字典序排序,如果你对同一个Key初始化了多个MultipartUpload,则其结果先按照Key排序,再按照UploadId排序。
Requests:
Syntax
GET /BucketName?uploads HTTP/1.1 Host: storage.jcloud.com Date: Date Authorization: signatureValue |
Request elements:
|
| 必要 | ||
key-marker | 与upload-id-marker一起使用,用来设置返回Multipart Upload的起始Key 如果upload-id-marker没有指定,则只有Multipart Upload的key的字典序大于key-marker时才会被返回 如果指定了upload-id-marker,那么key等于key-marker的Multipart Upload也会被返回,且在该条件下,返回Upload Id字典序大于upload-id-marker的Multipart Upload | 否 | ||
upload-id-marker | 与key-marker一起使用,若key-marker没有指定,则忽略该参数。若与key-marker同时指定,那么key等于key-marker的Multipart Upload也会被返回,且在该条件下,返回Upload Id字典序大于upload-id-marker的Multipart Upload | 否 | ||
max-uploads | 返回Multipart Upload信息的数量,最大为1000 | 否 | ||
prefix | 限制返回Multipart Upload中Object的Key的前缀 | 否 | ||
delimiter | 分组符,用于分组返回的Object的Key。当prefix未指定时,从Object的Key中提取第一个字符到第一个delimiter之间的字符串放在CommonPrefixes中返回。若指定了prefix,则提取prefix到第一个delimiter之间的字符串放在CommonPrefixes中返回,具体使用请参看后面的例子。 | 否 |
Responses
Response Headers:
见5.2.2节
Response Body:
Json格式的字符串,详见example
Response Elements
Name | Description |
Bucket | 桶名。Type: string |
Delimiter | 指定的Delimiter分组符。Type: String |
Prefix | 指定的Object Key的前缀。Type: String |
KeyMarker | 指定的KeyMarker 。Type: String |
UploadIdMarker | 指定的UploadIdMarker . Type: String |
NextKeyMarker | 当HasNext为true时,利用该值和NextUploadIdMarker来列出下一个集合 .Type: String |
NextUploadIdMarker | 当IsTruncated为true时,利用该值和NextKeyMarker来列出下一个集合 .Type: String |
MaxUploads | 指定的Multipart Upload的数量。Type: Integer |
HasNext | 标识返回的结果是否完整(true or false),若符合条件的Multipart Upload数目超过了指定的MaxUploads,则该值为True,且多余的结果也不会被返回。 。Type: bool |
Upload | 包含了一个Multipart Upload信息的容器 。Type: Container |
Key | 某个分块上传关联的对象名称,即 Object的Key .Type: Integer |
UploadId | Multipart Upload的Id . Type: Integer |
Initiated | multipart upload 初始化的时间。Type: Date |
CommonPrefixes | 用户指定了Delimiter时,该元素才会出现。用于存放分组后Object Key前缀。 。Type: Container |
Example:
Sample Request
GET /liningbo?uploads Date: Tue, 02 Jul 2013 02:30:29 GMT Authorization: jingdong 9c379f079214447fad2959c4621cd6feVb797oH1:uRQYWRPSAckYCyAwVWd4hK+BW1k= Host: storage.jcloud.com Connection: Keep-Alive User-Agent: JSS-SDK-JAVA/1.1.0 (Java 1.7.0_21; Vendor Oracle Corporation; Linux 3.5.0-17-generic; HttpClient 4.2.1) |
SampleResponse
200 Server: nginx/1.2.7 Date: Tue, 02 Jul 2013 02:33:26 GMT Content-Type: application/json;charset=UTF-8 Content-Length: 419 Connection: close
{"Bucket":"liningbo","Delimiter":null,"Prefix":null,"KeyMarker":null,"UploadIdMarker":null,"NextKeyMarker":null,"NextUploadIdMarker":null,"MaxUploads":2,"HasNext":false,"Upload":[{"Key":"myObject","UploadId":"129a345df24d46ffb1c111cb6c375f80","Initiated":"Tue, 02 Jul 2013 02:31:59 GMT"},{"Key":"testObject","UploadId":"1e34f32a9d1c40ccab504b3c39074dcc","Initiated":"Mon, 01 Jul 2013 09:16:47 GMT"}],"CommonPrefixes":[]} |