Amazon S3 REST API 详解

Posted sp42a

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Amazon S3 REST API 详解相关的知识,希望对你有一定的参考价值。

好久没有写博客,学期接近尾声,时间方面会宽松些了,其实想写的东西还挺多的。前段时间一个项目用到了几个云存储,其中就包括 Amazon S3,于是这篇文章主要分享一些 Amazon S3 Rest API 的经验(Amazon S3 还包括 SOAP API)。

首先还是要先说一下 Amazon S3,全称是 Amazon Simple Storage Service。EC2 和 S3 是 Amazon 最早推出的两项云服务。在传统的计算机领域,主要包括计算、存储、网络这几个方面, 在云计算时代,前两者分别对应虚拟化和 cloud storage,由此可以显现出 Amazon EC2 和 S3 的重要性。如今随着云计算的大红大紫,也有很多使用 Amazon S3 的例子,典型的有 Dropbox,还有之前被 FB 收购的 Instagram,其照片存储就使用的 S3。

关于 REST,这也是比较火的一种 Web 服务架构。简单来说,资源是由 URI 指定,对资源的操作包括 GET、PUT、POST、DELETE 和H EAD,返回结果常常是 XML 或者其他形式。如果你想了解更多,可以查看 REST 的 Wik i页面

Amazon S3 的操作包括三部分:Service,Buckets和Objects。Service 只包括 GET 操作,就是返回所有的 Buckets 的列表。Object 顾名思义,是指存储在云端的文件,值得注意的是,S3 中并没有明确的文件夹的概念,而是通过指定 object 的路径来实现,比如说,object 可以为 “photos/1.jpg”。而 Bucket 拥有全局名,名称由用户定义,用来存放 Object,由于是全局名,所以要确保名字是别人没用过的。

访问 Web 服务时,Http request headers 需要一些参数。主要包括:

  • Date:当前 UTC 时间,形式为 “Wed, 01 Mar 2009 12:00:00 GMT”。
  • Content-Length: 当对 Object 进行操作的时候,返回内容的长度,注意不要包括 headers 中的内容。
  • Content-MD5:用 base64 编码文件内容的 MD5 值。
  • Content-Type:资源的类型,比如:text/plain
  • Host:Get Service 时为“ s3.amazonaws.com”。在对 bucket 和 object 进行操作时,例如bucket的名字是“bucketname”,那么 Host 就是“bucketname.s3.amazonaws.com”。
  • x-amz-meta-x-am- 开头的:包括 Amazon 定义的一些元数据和一些特定的 header。后面如果出现会提到。
  • Authorization:这个是最重要的,主要作用是签名,Amazon 根据的请求计算出一个签名值和这里计算的签名值进行比对,只有相同时,访问才是合法的。接下来对 Authorization 的计算方法进行详述。

Authorization 的计算方法

这个是 Amazon 文档中的说明:

Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature;

Signature = Base64( HMAC-SHA1( UTF-8-Encoding-Of(YourSecretAccessKey), UTF-8-Encoding-Of( StringToSign ) ) );

StringToSign = HTTP-Verb + "\\n" +
	Content-MD5 + "\\n" +
	Content-Type + "\\n" +
	Date + "\\n" +
	CanonicalizedAmzHeaders +
	CanonicalizedResource;

CanonicalizedResource = [ "/" + Bucket ] +
	<HTTP-Request-URI, from the protocol name up to the query string> +
	[ subresource, if present. For example "?acl", "?location", or "?logging"];

CanonicalizedAmzHeaders = <described below>

首先 Authorization 是由”AWS 0:1“组成的,第0个参数为你的 Access Key ID,在注册了 AWS 之后,在这里可以得到。第1个参数是计算出来的签名值。

签名值的计算方法是对一个 UTF-8 的字符串,用你的 Secret Access Key(同样在 Access Key ID 处获取)进行 SHA1 加密。

StringToSign 字符串也需要满足一定的格式。如上所示,第一行是你的操作名,应该为 PUT、GET、DELETE、HEAD 和 POST 中的一种。第二行是内容的 MD5 值的 base64 编码,和 headers 中的 Content-MD5 值应保持一致。第三行是Content-Type,同样需要和headers中的一致。第四行 Date,和 headers 中的 Date 一致。需要说明的是 CanonicalizedAmzHeaders 和 CanonicalizedResource。

CanonicalizedAmzHeaders 就是把 headers 中的 x-amz- 开头的作为 key 转化为小写并按顺序排列,key 和 value 之间用冒号相连,用换行符“\\n”把它们给连接起来。比如说 headers 中有:

X-Amz-Meta-ReviewedBy: joe@johnsmith.net 
X-Amz-Meta-ReviewedBy: jane@johnsmith.net 
X-Amz-Meta-FileChecksum: 0x02661779 
X-Amz-Meta-ChecksumAlgorithm: crc32

那么CanonicalizedAmzHeaders就是:

x-amz-meta-checksumalgorithm:crc32\\n
x-amz-meta-filechecksum:0x02661779\\n
x-amz-meta-reviewedby:joe@johnsmith.net,jane@johnsmith.net

CanonicalizedResource 是指规范化的资源。如果访问资源没有指定 bucket,那么就是“/”;如果包括 bucket,而不包括 object,那就是“/bucket_name/”,注意前后的“/”不要落了;如果既包括 bucket,也包括 object,那么就是“/bucket_name/object_name”;另外,有时候比如是访问 bucke t的 acl(访问控制列表 acess control list)时,object_name 就是 ?acl,因此这时 CanonicalizedResource就是“/bucket_name/?acl”,访问 object 的 acl 时,CanonicalizedResource 就是“/bucket_name/object_name?acl”。

需要说明的是,如果计算出的 CanonicalizedAmzHeaders 不为空时,要确保 CanonicalizedAmzHeaders 和 CanonicalizedResource 之间有换行符“\\n”连接。

关于 Authorization 的详细内容,可以参考官方文档

Service

对 Service的 操作只包括 Get,即获取用户所有的 Buckets 列表。Request headers 除了通用的,没有其他的内容。比如

GET / HTTP/1.1
Host: s3.amazonaws.com
Date: date
Authorization: signatureValue

返回的 XML 中包括 Owner 和各个 Buckets,比如:

<?xml version="1.0" encoding="UTF-8"?>
<ListAllMyBucketsResult xmlns="http://doc.s3.amazonaws.com/2006-03-01">
  <Owner>
    <ID>bcaf1ffd86f461ca5fb16fd081034f</ID>
    <DisplayName>webfile</DisplayName>
  </Owner>
  <Buckets>
    <Bucket>
      <Name>quotes</Name>
      <CreationDate>2006-02-03T16:45:09.000Z</CreationDate>
    </Bucket>
    <Bucket>
      <Name>samples</Name>
      <CreationDate>2006-02-03T16:41:58.000Z</CreationDate>
    </Bucket>
  </Buckets>
</ListAllMyBucketsResult>

Buckets

由于项目中只用到了 Buckets 的 PUT、GET、DELETE,关于 acl、lifecycle、policy 等就不作过多说明,如果这方面有疑问,可以参考官方文档

接下来,如果 Http request headers 中内容没有什么特别说明的,将会略去不写。

PUT Bucket

需要说明的是,在 request headers 可以加入 bucket 的权限控制,即指定 x-amz-acl,合法的值包括:private,public-read、public-read-write、authenticated-read、bucket-owner-read、bucket-owner-full-control,从名字就可以看出具体的含义。

在 request body 中可以包括位置信息,即用户期望 Bucket 放置在 Amazon 的哪个数据中心。默认为 US Standard,其他数据中心包括 US West (Oregon) Region、US West (Northern California) Region、EU (Ireland) Region、Asia Pacific (Singapore) Region、Asia Pacific (Tokyo) Region、South America (Sao Paulo) Region。对于我们中国用户来说,离得最近的是东京的数据中心。不过在 body 中内容中,这七个数据中心写成:‘EU’、 ‘eu-west-1’、‘us-west-1’、 ‘us-west-2’、‘ap-southeast-1’、‘ap-northeast-1’ 和 ‘sa-east-1’。

比如请求如下:

PUT / HTTP/1.1
Host: BucketName.s3.amazonaws.com
Content-Length: length
Date: date
Authorization: signatureValue

<CreateBucketConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 
  <LocationConstraint>BucketRegion</LocationConstraint> 
</CreateBucketConfiguration>

GET Bucket

Get Bucket 主要是列出这个 Bucket 下所有的 objects。值得提的是四个参数 Prefix、Marker、MaxKeys 和 Delimiter,利用这四个参数,可以达到多种效果。

首先是 Prefix,它表示这个 Bucket 中返回的 Object 以这个值为开头。Marker 表示,返回这个值以后的 Objects,比如说第一次调用没有返回全部结果,则把第一次调用返回的 Objects 的最后一个作为 Maker 调用,以返回其以后的 Objects。MaxKeys 返回单次请求返回的最大 Objects 数,默认为 1000。Delimiter 表示分隔符,是在设置了 Prefix 之后,能够返回共同的 Prefix(在结果中为 CommonPrefix)。

因此,通过设置 MaxKeys和Marker可以达到翻页效果,每次返回的最后一个 Object 作为下一次请求的 Marker,在返回值中,如果 IsTruncated 为 true,那么表示还有下一页。此外,通过设置 Prefix 和将 Delimiter 设为”/“,可以达到返回某个文件夹下所有内容的效果,其中 CommonPrefix 下的 Prefix 表示文件夹路径,而每个 Contents 中是 Object 的信息。

下面是一个请求的例子:

GET ?prefix=N&marker=Ned&max-keys=40 HTTP/1.1
Host: quotes.s3.amazonaws.com
Date: Wed, 01 Mar  2009 12:00:00 GMT
Authorization: AWS AKIAiosFODNN7EXAMPLE:xQE0diMbLRepdf3YB+FIEXAMPLE=

返回结果为:

HTTP/1.1 200 OK
x-amz-id-2: gyB+3jRPnrkN98ZajxHXr3u7EFM67bNgSAxexeEHndCX/7GRnfTXxReKUQF28IfP
x-amz-request-id: 3B3C7C725673C630
Date: Wed, 01 Mar  2009 12:00:00 GMT
Content-Type: application/xml
Content-Length: 302
Connection: close
Server: AmazonS3

<?xml version="1.0" encoding="UTF-8"?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <Name>bucket</Name>
    <Prefix/>
    <Marker/>
    <MaxKeys>1000</MaxKeys>
    <IsTruncated>false</IsTruncated>
    <Contents>
        <Key>my-image.jpg</Key>
        <LastModified>2009-10-12T17:50:30.000Z</LastModified>
        <ETag>"fba9dede5f27731c9771645a39863328"</ETag>
        <Size>434234</Size>
        <StorageClass>STANDARD</StorageClass>
        <Owner>
            <ID>75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a</ID>
            <DisplayName>mtd@amazon.com</DisplayName>
        </Owner>
    </Contents>
    <Contents>
       <Key>my-third-image.jpg</Key>
         <LastModified>2009-10-12T17:50:30.000Z</LastModified>
        <ETag>"1b2cf535f27731c974343645a3985328"</ETag>
        <Size>64994</Size>
        <StorageClass>STANDARD</StorageClass>
        <Owner>
            <ID>75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a</ID>
            <DisplayName>mtd@amazon.com</DisplayName>

DELETE Bucket

DELETE Bucket 没有什么需要特殊说明的。

Objects

PUT Object
PUT Object 基本操作类似,在 Http body 中添加 Object 的内容,这里就需要计算 Content-Type 等值。与 PUT Bucket 类似,可以在 Http headers 中加入 x-amz-acl,以控制 Object 的权限。

GET Object

在 GET Object 时,Response headers 中会包括这个 Object 的相关信息,除了 Content-Length 和 Content-Type 等,Etag 其实就是内容的 MD5 后的16进制的字符串。而 Response body 中就是文件的内容。

DELETE Object

DELETE 操作仍然没有什么特别说明的。

综上,本文主要说明了 Amazon S3 中对 Service 的 GET,以及对 Bucket 和 Object 的 PUT、GET 和 DELETE 操作。但是 REST API中 还有一部分没有提到,这个可以查看具体的文档,其中解释得还是比较详细的。这篇文章还是为了想写 Amazon S3 客户端调用的同学们提供导向作用。

最后提及一下当时的项目,项目主要是要实现一个本地的多云存储的备份。我们的项目使用了 Python,而 Amazon S3 有一些第三方的 API 调用的实现,比较知名的有 Boto,但是由于其支持很多云服务,显得过于庞大,最后我决定自己实现,而 Amazon S3 这块的中文资料也不是很多,这里分享出来,让入门的同学能够更快的上手,仅此而已。如果想看我们项目中 Amazon S3 REST API 的客户端实现,可以移步这里

以上是关于Amazon S3 REST API 详解的主要内容,如果未能解决你的问题,请参考以下文章

SignatureDoesNotMatch - Amazon S3 API

Amazon S3 对象存储Java API操作记录(Minio与S3 SDK两种实现)

ElasticSearch 中 REST API 详解

Amazon S3 POST api,并使用 NodeJS 签署策略

使用 Amazon api 网关用 REST API 包装 graphQL(appsync)

适用于 Amazon Redshift 的 REST API