以下的操作基于REST,官方文档:http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAuthentication.html 我们的程序向http://bucket.s3.amazonaws.com/(或者http://s3.amazonaws.com/bucket/)发送带指定header的HTTP::Request,S3接到请求后,进行处理,将处理结果返回HTTP::Response,程序处理HTTP::Response。 下面以上传一个文件举例说明,程序使用perl实现。 1、假设已经有一个bucket,名字为:buckettest; 2、用HTTP::Request的PUT方法上传文件; 3、使用HTTP标准Authorization头发送验证信息;这个验证的格式为:
Authorization: AWS AWSAccessKeyId:Signature
AWS后面的是一个空格; AWSAccessKeyId是第一篇文章中说的Access Key ID,假设为0PN5J17HBGZHT7JJ3X82; Signature是一个加密后再用Base64编码的串。
Signature = Base64( HMAC-SHA1( UTF-8-Encoding-Of( StringToSign ) ) );
有关HMAC-SHA1的算法请参见:RFC 2104 - Keyed-Hashing for Message Authentication。 StringToSign的组成如下:
StringToSign = HTTP-Verb + “\n” + Content-MD5 + “\n” + Content-Type + “\n” + Date + “\n” + CanonicalizedAmzHeaders + CanonicalizedResource;
HTTP-Verb就是HTTP的方法,本例中,为PUT; Content-MD5我没有用到,也没有研究,可以看看这里:RFC 1864 - The Content-MD5 Header Field。如果不用的话,为空("")即可; Content-Type是PUT文件的文件类型,比如image/jpeg,text/plain; Date是GMT ASCII格式:Sun, 06 Nov 1994 08:49:37 GMT。perl下,HTTP::Date的time2str即可返回; CanonicalizedAmzHeaders,使用小写字符串。用于记录Amazon自己定义的信息。比如,上传文件同时将文件设置为所有人只读,那么就需要添加x-amz-acl:public-read\n到CanonicalizedAmzHeaders。如果浏览器不支持Date头,或者同时需要传递2个时间,那么可使用x-amz-date:Sun, 06 Nov 1994 08:49:37 GMT\n(时间格式同Date)。如果想给对象附加一些自定义信息,那么还可以使用x-amz-meta-xxx:xxx\n,比如x-amz-meta-reviewedby:x@xx.cn,y@xx.cn\n CanonicalizedResource的组成如下:
CanonicalizedResource = [ “/” + Bucket ] + <HTTP-Request-URI, from the protocol name up to the query string> + [ sub-resource, if present. For example “?acl”, “?location”, “?logging”, or “?torrent”];
"/" + Bucket仅用在虚拟主机类型下,请查看这里Virtual Hosting of Buckets。 HTTP-Request-URI,比如我们把文件上传为:/buckettest/software/winzip.txt。 sub-resource,比如acl操作对象的权限;location操作对象的位置:美国还是欧洲;logging处理对象操作记录;使用torrent方式下载文件; 比如我们上传一个文本文件到指定目录,然后设置这个文件为所有人均可访问,同时附加2个email地址供以后使用,则StringToSign为:
PUT\n \n text/plain\n Sun, 06 Nov 1994 08:49:37 GMT\n x-amz-acl:public-read\n x-amz-meta-reviewedby:x@xx.cn,y@xx.cn\n /buckettest/software/winzip.txt
=>
PUT\n\ntext/plain\nSun, 06 Nov 1994 08:49:37 GMT\nx-amz-acl:public-read\nx-amz-meta-reviewedby:x@xx.cn,y@xx.cn\n/buckettest/software/winzip.zip
然后可以获得Signature,假设是:hcicpDDvL9SsO6AkvxqmIWkmOuQ=。第一个头Authorization就有了:
$http_header->header(‘Authorization’ => ‘AWS 0PN5J17HBGZHT7JJ3X82:hcicpDDvL9SsO6AkvxqmIWkmOuQ=’);
4、其他头 这个由Signature决定,本例中,我们使用了content-type、Date、x-amz-acl和 x-amz-meta-reviewedby,那么这些都要加到头里面。
$http_header->header(‘content-type’, ’text/plain’); $http_header->header(‘Date’, ‘Sun, 06 Nov 1994 08:49:37 GMT’); $http_header->header(‘x-amz-acl’, ‘public-read’); $http_header->header(‘x-amz-meta-reviewedby’, ‘x@xx.cn,y@xx.cn’);
5、发送请求
my $request = HTTP::Request->new(“PUT”, “http://buckettest.s3.amazonaws.com/software/winzip.txt", $http_headers); $request->content(“this is a test”); my $response = LWP::UserAgent->new()->request($request);
如果Response Code为200,则表示上传成功。如果上传失败,S3会返回错误信息,对照处理即可。