从 Amazon S3 查询和下载

工程 | Ben Hale | 2007年4月30日 | ...

在之前的文章中,我描述了我们如何使用自定义 ANT 任务来上传 Spring 产品组合中基于 ANT 的项目的夜间快照。在这篇文章中,我将描述我们如何使用 Amazon S3 为每个项目的快照生成页面并允许用户下载快照。

正如我在上一篇文章中提到的,S3 主要用作 RESTful 服务。这意味着虽然我使用 Java 来进行上传部分,但我可以自由地使用其他语言来进行下载部分。在这种情况下,我选择使用 PHP,因为它已经安装在我的工作服务器上,并且是最简单的方案。

这项工作分为两个部分。首先,我需要查询 Amazon S3 服务以获取给定 Spring 项目的快照列表。为此,您可以创建一个带有前缀参数的 REST 查询。


http://s3.amazonaws.com/static.springframework.org/?prefix=$prefix

既然您已经了解了查询的基本方法,我想回到之前的示例,并指出上传定义中的一些重要部分。


<aws:s3 accessKey="${s3.accessKey}" secretKey="${s3.secretKey}">
	<upload bucketName="static.springframework.org"
		file="${target.release.dir}/${release-with-dependencies.zip}"
		toFile="SPR/spring-framework-${spring-version}-with-dependencies-${tstamp}-${build.number}.zip"
		publicRead="true"/>
	<upload bucketName="static.springframework.org"
		file="${target.release.dir}/${release.zip}"
		toFile="SPR/spring-framework-${spring-version}-${tstamp}-${build.number}.zip"
		publicRead="true"/>
</aws:s3>

首先你会注意到,对于 Spring 工件,我选择以SPR作为前缀。文件名基本上是自由格式的,因此您可以使用斜杠创建虚拟目录结构来进行查询。如果您查看 Spring Web Flow 的构建,您会看到其工件以SWF作为前缀,Spring LDAP 的工件以LDAP作为前缀,Spring Modules 的工件以MOD作为前缀。因此,现在通过自定义我们的查询参数,我们可以专门选择一个项目。


http://s3.amazonaws.com/static.springframework.org/?prefix=SPR

http://s3.amazonaws.com/static.springframework.org/?prefix=SWF

http://s3.amazonaws.com/static.springframework.org/?prefix=LDAP

http://s3.amazonaws.com/static.springframework.org/?prefix=MOD

第二点需要注意的是publicRead=true声明。默认情况下,S3 不允许任何人查看或下载您的存储桶中的内容。您可以使用您的密钥和访问密钥创建令牌来授予他们权限,从而允许下载。但是,对于这项工作,我认为没有必要。快照是公开可访问的,所以我放松了安全性,允许它们无需令牌即可下载。

现在您可以调用 S3 REST 服务并获取存储桶中项目的已正确过滤的列表,但是响应是原始 XML。即使我是 Spring 开发人员,在 Web 浏览器中查看原始 XML 也并不会让我兴奋。;) 所以下一步是将 XML 转换为有用的 HTML 页面。此时我有两种选择。我可以执行服务器上的转换以生成 HTML,然后将其返回给用户,或者我可以将 XML 与 XSLT 文件一起返回给用户,并让用户的浏览器为我执行转换。老实说,后者减轻了服务器的负载,实际上允许用户的浏览器缓存转换以提高性能。但现实情况是,我没有访问 XSLT PHP 库,所以如果我想的话,我无法进行服务器端转换。我意识到一些旧的浏览器在这个设置下会有问题,但是我们会到时候再解决这个问题。

所以我需要获取返回的 XML


<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
	<Name>static.springframework.org</Name>
	<Prefix>SPR</Prefix>
	<Marker/>
	<MaxKeys>1000</MaxKeys>
	<IsTruncated>false</IsTruncated>
	<Contents>
		<Key>SPR/spring-framework-2.0.5-20070411-50.zip</Key>
		<LastModified>2007-04-11T13:27:34.000Z</LastModified>
		<ETag>"1ab20ad18ca0edb4a360279f27409d54"</ETag>
		<Size>10725241</Size>
		<StorageClass>STANDARD</StorageClass>
	</Contents>
	<Contents>
		<Key>SPR/spring-framework-2.0.5-20070411-51.zip</Key>
		<LastModified>2007-04-12T01:25:58.000Z</LastModified>
		<ETag>"de2e5833ae8fe4cc06987935bea06e57"</ETag>
		<Size>10727049</Size>
		<StorageClass>STANDARD</StorageClass>
	</Contents>
	<Contents>
		<Key>SPR/spring-framework-2.0.5-20070412-52.zip</Key>
		<LastModified>2007-04-13T01:22:23.000Z</LastModified>
		<ETag>"414b947226fc4e08bd118e0f16a6be67"</ETag>
		<Size>10736732</Size>
		<StorageClass>STANDARD</StorageClass>
	</Contents>
...

并将其转换为 HTML

snapshot-download.png

从服务返回的大部分内容对这项工作没有用,因此 XSLT 变得非常简单。


<xsl:template match="/">
	<head>
		<style type="text/css" media="all">@import "./snapshot-download.css";</style>
	</head>
	<body>
		<xsl:apply-templates select="s3:ListBucketResult"/>
	</body>
</xsl:template>

<xsl:template match="s3:ListBucketResult">
	<xsl:variable name="bucket-name" select="s3:Name"/>
	<table>
		<tr>
			<th class="name"><xsl:value-of select="s3:Prefix"/> Project Snapshots</th>
			<th class="size">Size</th>
		</tr>
		<xsl:for-each select="s3:Contents">
			<tr>
				<td class="name">
					<a class="name" href="http://s3.amazonaws.com/{$bucket-name}/{s3:Key}">
						<xsl:value-of select="substring-after(s3:Key, '/')"/>
					</a>
				</td>
				<td class="size"><xsl:value-of select="format-number(s3:Size div 1048576, '###,###.0')"/> MB</td>
			</tr>
		</xsl:for-each>
	</table>
</xsl:template>

转换以一些 HTML 声明开头,然后迭代存储桶的每个项目。然后它使用对象标识符来创建指向 S3 服务器上文件的链接。就是这样。PHP 页面调用 S3 获取 XML,然后将其与 XSLT 声明一起传递给用户的浏览器。


<?php
$prefix = $HTTP_GET_VARS["project"];
$url = "http://s3.amazonaws.com/static.springframework.org/?prefix=$prefix";
$xml = file_get_contents($url);

header('Content-Type: text/xml; charset=UTF-8');
echo '<?xml version="1.0" encoding="UTF-8"?>';
echo '<?xml-stylesheet type="text/xsl" href="./snapshot-download.xsl"?>';
echo substr($xml, 39);
?>

使用请求参数为每个项目添加一些自定义内容,您将获得每个项目的单独下载页面。

这就完成了我对 Amazon S3 服务的探索。我现在可以根据经验说,如果您有大量数据和大量的带宽需求,没有多少地方能给您提供更好的价格。并且使用 RESTful 接口,它足够灵活,可以与您最喜欢的语言一起使用。感谢您的参与,我现在接受任何问题。:)

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获得支持

Tanzu Spring在一个简单的订阅中提供对OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部