亚马逊网络服务

作者:Reuven M. Lerner

在我上大学的时候,购买技术书籍的选择并不多。我可以去价格昂贵的校园书店购买新书,可以去街角一家价格同样昂贵的竞争对手那里购买,或者我可以从其他学生那里购买旧书,他们在每个学期末都会宣传他们的商品。无论如何,我购买书籍的能力取决于我的地理位置,以及我了解可购买书籍的能力。

所以,当得知我是在线书店的早期顾客时,您可能不会感到惊讶,早在 1995 年夏天之前,我就光顾了 Bookpool 和亚马逊。优惠的价格和广泛的选择,以及便利性,简直是梦想成真。即使我可能不愿意承认,我可能从在线商店购买书籍的钱和我在实体店花费的钱一样多。然而,虽然我的购书预算没有改变,但我可以购买的书籍数量,以及可供选择的种类,在实体世界中是无与伦比的。

当亚马逊向第三方书商敞开大门时,情况变得更好了。现在,我不仅可以舒适地坐在客厅里比较新书的价格,还可以浏览和购买二手书。低于 1 美元(加上运费)的有趣书籍的数量,已经把我变成了一个购书狂;我研究生办公室的书架上堆满了书籍,我希望这些书对我的研究有用,但我购买它们很大程度上是因为机会来了。当我听说一本有趣的书时,我的第一反应现在是查看亚马逊——或者更好的是 isbn.nu,它可以比较多个网站的价格。

多年来,亚马逊已经建立了一个庞大的图书信息数据库。我确信,这个关于书籍、买家和卖家的数据库仍然是亚马逊决策者的重要信息来源。但几年前,亚马逊决定做一件令人惊讶的事情——他们将内部数据库的一部分向第三方开发者开放,这个项目被称为亚马逊网络服务 (AWS)。通过使用 AWS,开发者可以使用客户端程序而不是 Web 浏览器,来执行几乎他们通常在亚马逊网站上能够做的每一项任务。AWS 还包括许多针对书商的功能,用于定价和库存管理。

在 2005 年下半年,亚马逊推出了一系列新的举措,这些举措都属于其“网络服务”的范畴,其中只有一部分与直接销售和购买书籍有关。大约在同一时间,eBay 宣布将不再向开发者收取使用其网络服务的费用,这使得查询两个最大的销售数据数据库成为可能。当然,谷歌长期以来也提供自己的网络服务;尽管数据目前仅限于主索引,但可以肯定地认为它是一个巨大的资源。

本月,我们将开始探索商业网络服务的世界,特别关注如何将来自外部网络服务的数据集成到我们自己的应用程序中。在此过程中,我们将看到调用网络服务的一些不同方式,一些可供我们选择的不同产品,以及我们如何能够基于现有的网络服务来创建新的和有趣的应用程序。

什么是网络服务?

在 Web 的最初十年左右,它主要被设计用于用户交互。也就是说,大多数 HTTP 客户端是 Web 浏览器,而这些浏览器下载的大部分内容是 HTML 格式的文本,供人们阅读。

在某个时候,开发者开始考虑他们可以使用 HTTP 做更多的事情,而不仅仅是传输人类可读的文档。他们开始使用 HTTP 在程序之间传输数据。HTTP 作为传输协议和 XML 作为数据格式的结合,催生了 XML-RPC。由于 XML 和 HTTP 是平台无关的,因此不必使用相同的语言编写客户端和服务器程序,甚至不必使用相同的操作系统。因此,XML-RPC 提供了一种实现跨平台 RPC(远程过程调用)的方法,与解决相同问题的其他类似方法(例如,CORBA 中间件)相比,开销要小得多。

XML-RPC 过去是,现在仍然是一个良好、简洁和轻量级的协议,但它缺乏许多开发者想要的复杂性、错误处理和数据类型。因此,SOAP(最初是简单对象访问协议的缩写)引入了许多扩展,使其更加正式,包括消息信封和正文的分离。

XML-RPC 和 SOAP 都假定服务器将在特定的 URL 上监听方法调用。因此,服务器可能在 /server 或 /queries 或类似的 URL 上有一个 XML-RPC 或 SOAP 服务器在监听。然后,客户端负责在请求中指示它需要哪个方法。在 XML-RPC 中,我们使用 methodName 标签。参数和元数据都包含在 XML 信封中传递,该信封作为 HTTP POST 提交的一部分发送。

另一种称为 REST 的技术,在 URL 本身中标识方法调用。它像标准的 GET 请求一样传递参数。REST 有许多优点,尤其是其实现和使用的简单性。而且,调试 REST 很容易,因为您可以将 URL 输入 Web 浏览器而不是专用程序。但是,当处理复杂的数据结构时,仍然有很多人在使用 SOAP 和 XML-RPC。

网络服务构成了高科技世界中越来越为人所知的面向服务架构或 SOA 的核心。网络服务汇集了 Web 的所有优势——平台独立性、语言独立性以及在无需分发新版本的情况下升级和更改服务的能力。

SOA 使创建新服务,甚至发布现有服务的新版本成为可能,可以通过替换现有实现或与旧实现并行发布新实现来实现。那些使用网络服务的人可以受益于更高的速度和效率,或者完全新的 API,而无需担心不兼容性或安装问题。此外,只要开发者遵循服务发布的规范,他们就可以使用他们想要的任何语言和平台,创建从交互式桌面应用程序到处理千兆字节数据的自动化批处理作业的任何东西。

亚马逊的网络服务

亚马逊是最早开始使用网络服务的公司之一。AWS 现在是一套不同的 API,其中一些与亚马逊的商品目录有关,而另一些(例如,Mechanical Turk 和亚马逊的简单队列服务)是更通用的服务。最受欢迎的服务被称为电子商务服务 (ECS)。ECS 使从亚马逊的几个商店检索产品数据、获取有关特定商品和供应商的详细信息,以及执行与电子商务相关的基本操作(包括购物车的创建和操作)成为可能。

ECS 有两种基本的操作模式,称为搜索和查找。搜索返回与一组条件匹配的产品列表——例如,Larry Wall 编写的所有书籍,或者标题中包含单词 Python 的书籍,或者 Woody Allen 导演的电影。查找用于当您知道与产品关联的特定 ID 代码时,该代码称为 ASIN(亚马逊标准 ID 号)。书籍的 ASIN 与其国际标准书号 (ISBN) 相同;其他类型的产品有亚马逊定义的 ASIN。

因此,假设我感兴趣的是了解亚马逊是否库存了 Pragmatic Programmers 关于 Ruby on Rails 的书籍,以及它的价格。因为我正在寻找特定的商品,所以我应该使用 ItemLookup 操作。但这意味着我需要知道 ISBN,我发现是 097669400X。(ECS 期望 ISBN 不带任何连字符或其他标点符号。)最后,我必须获得 AccessKeyId 的值,这是一个 ID 号,它告诉亚马逊哪个开发者正在访问系统。(获取 AccessKeyId 是免费且容易的;请参阅在线资源了解详细信息。)

ECS REST 请求的基本 URL 是 http://webservices.amazon.com/onca/xml?Service=AWSEcommerceService。

为了指示操作、AccessKeyId 和 ItemId,我们将名称-值对添加到 URL 上,使用 name=value 格式,并用 & 符号分隔这些对。我们组合后的 URL 如下所示:http://webservices.amazon.com/onca/xml?Service=AWSEcommerceService&Operation=ItemLookup&AWSAccessKeyId=XXX&ItemId=0735619530。

如果您将上述内容放入 Web 浏览器(将 XXX 替换为实际的 AccessKeyId 值),您应该会看到从亚马逊服务器返回的 XML 文档(内容类型为 text/xml)。该文档以 ItemLookupResponse 标签开头,然后分为两个部分:OperationRequest(描述您发出的请求,包括浏览器的 UserAgent 标头以及您传递给服务的所有参数)和 Items(包含来自亚马逊的响应)。

例如,这是我收到的来自亚马逊请求的响应

<ItemLookupResponse>
    <OperationRequest>
    <HTTPHeaders>
        <Header Name="UserAgent" Value="Mozilla/5.0 (Macintosh; U; PPC
Mac OS X Mach-O; en-US; rv:1.8) Gecko/20051111 Firefox/1.5"/>
    </HTTPHeaders>
    <RequestId>1NBTWT1FHDEHJK2G16CT</RequestId>
    <Arguments>
        <Argument Name="Operation" Value="ItemLookup"/>
        <Argument Name="Service" Value="AWSECommerceService"/>
        <Argument Name="AWSAccessKeyId" Value="XXX"/>
        <Argument Name="ItemId" Value="097669400X"/>
    </Arguments>
    <RequestProcessingTime>0.00745105743408203</RequestProcessingTime>
    </OperationRequest>

    <Items>
    <Request>
    <IsValid>True</IsValid>
    <ItemLookupRequest>
    <ItemId>097669400X</ItemId>
    </ItemLookupRequest>
    </Request>
    <Item>
        <ASIN>097669400X</ASIN>
        <DetailPageURL>
http://www.amazon.com/exec/obidos/redirect?tag=
↪ws%26link_code=xm2%26camp=2025%26creative=
↪165953%26path=http://www.amazon.com/gp/
↪redirect.html%253fASIN=097669400X%2526tag=
↪ws%2526lcode=xm2%2526cID=2025%2526ccmID=
↪165953%2526location=/o/ASIN/
↪097669400X%25253FSubscriptionId=XXX
        </DetailPageURL>
        <ItemAttributes>
        <Author>Dave Thomas</Author>
        <Author>David Hansson</Author>
        <Author>Leon Breedt</Author>
        <Author>Mike Clark</Author>
        <Author>Thomas Fuchs</Author>
        <Author>Andrea Schwarz</Author>
        <ProductGroup>Book</ProductGroup>
        <Title>
        Agile Web Development with Rails (The Facets of Ruby Series)
        </Title>
        </ItemAttributes>
    </Item>
    </Items>
</ItemLookupResponse>

在前面的 XML 中,有几个特别有用的字段。您可以看到亚马逊处理我们的请求花费了多少时间(在本例中为 0.008 秒),如果我们需要调试和/或基准测试我们的应用程序,这可能很有用。DetailPageURL 包含我们可以将希望查看亚马逊网站上有关此产品信息的用户的 URL。而且,我们获得了诸如标题和作者之类的信息,这些信息在显示书籍信息时可能很有用。

实际上,应该很容易看出我们如何解析这个 XML,在 Web、GUI 或控制台应用程序中显示它的部分或全部。或者,我们可以将此数据的一部分添加到我们正在创建的更大的数据库应用程序中,确保不违反亚马逊对检索数据使用的限制。

响应组

虽然上述信息很有用,但它仍然没有回答我最初的所有问题,即亚马逊是否库存了 Pragmatic Programmers 关于 Ruby on Rails 的书籍,以及它的价格。我知道 Rails 书籍可以从亚马逊购买,但我不知道它的价格。这是因为 ECS 默认返回少量数据,对应于我们上面看到的数据。我们可以通过指定一个或多个响应组,来定制亚马逊返回给我们的信息。每个响应组对应于 ECS 将在其响应中返回的一种或多种类型的数据。

因此,要获得关于书籍的基本定价信息,我们可以要求查看 OfferSummary 响应组:http://webservices.amazon.com/onca/xml?Service=AWSEcommerceService&Operation=ItemLookup&AWSAccessKeyId=XXX&ItemId=0735619530&ResponseGroup=OfferSummary“。

与之前的列表(描述书籍本身)不同,我们现在获得了一个特定书籍的最低新价格和二手价格的列表。以下是来自上述查询的 XML 响应

<ItemLookupResponse>
<OperationRequest>
<HTTPHeaders>
<Header Name="UserAgent" Value="Mozilla/5.0 (Macintosh; U; PPC Mac
OS X Mach-O; en-US; rv:1.8) Gecko/20051111 Firefox/1.5"/>
</HTTPHeaders>
<RequestId>0SNXJ8T5V2JA18M8AJQC</RequestId>
<Arguments>
<Argument Name="ResponseGroup" Value="OfferSummary"/>
<Argument Name="Operation" Value="ItemLookup"/>
<Argument Name="Service" Value="AWSECommerceService"/>
<Argument Name="AWSAccessKeyId" Value="XXX"/>
<Argument Name="ItemId" Value="097669400X"/>
</Arguments>
<RequestProcessingTime>0.0331768989562988</RequestProcessingTime>
</OperationRequest>
<Items>
	<Request>
	<IsValid>True</IsValid>
	<ItemLookupRequest>
	<ItemId>097669400X</ItemId>
	<ResponseGroup>OfferSummary</ResponseGroup>
	</ItemLookupRequest>
	</Request>
	<Item>
	<ASIN>097669400X</ASIN>
	<OfferSummary>
	<LowestNewPrice>
	<Amount>2295</Amount>
	<CurrencyCode>USD</CurrencyCode>
	<FormattedPrice>$22.95</FormattedPrice>
	</LowestNewPrice>
	<LowestUsedPrice>
	<Amount>2341</Amount>
	<CurrencyCode>USD</CurrencyCode>
	<FormattedPrice>$23.41</FormattedPrice>
	</LowestUsedPrice>
	<LowestCollectiblePrice>
	<Amount>3495</Amount>
	<CurrencyCode>USD</CurrencyCode>
	<FormattedPrice>$34.95</FormattedPrice>
	</LowestCollectiblePrice>
	<TotalNew>41</TotalNew>
	<TotalUsed>12</TotalUsed>
	<TotalCollectible>2</TotalCollectible>
	<TotalRefurbished>0</TotalRefurbished>
	</OfferSummary>
	</Item>
</Items>
</ItemLookupResponse>

正如您所看到的,响应的初始部分是相同的。但是响应的后半部分,在 <Items> 标签内,是不同的,带有 LowestNewPrice、LowestUsedPrice 和 LowestCollectiblePrice 标签,显示了我们可以购买这本书的价格。

我们还可以要求其他响应组,并根据需要混合和匹配它们的名称。例如,我们可以请求 Medium 响应组,这不仅为我们提供了关于请求和书籍的信息,还提供了与书籍相关的图像(多种尺寸)、书籍的尺寸和重量以及编辑评论。如果我们想更进一步,获取亚马逊客户留下的书籍评论和类似产品列表,我们可以请求 Large 响应组。

总结

亚马逊的网络服务为我们提供了一个工具,用于查找庞大的产品信息数据库,供个人和商业用途。此外,ECS 让我们体验了创建 REST 风格查询的感觉,以及我们如何解析结果。最后,正如 Web 开发者经常从现有网站上的 HTML 和 JavaScript 中学习一样,我们可以通过研究亚马逊如何构建他们的网络服务,来学习如何为我们自己创建好的网络服务。特别是,我喜欢亚马逊的响应组概念,它允许我们混合和匹配我们可能获得的响应类型——这可能是我会在自己的网络服务中效仿的东西。

下个月,我们将在此处看到的基础上,创建我们自己的网络服务,该服务聚合来自亚马逊和我当地公共图书馆的数据,以为我提供个性化的图书查找系统。

本文资源: /article/8748

Reuven M. Lerner 是一位长期的 Web/数据库顾问,是西北大学学习科学专业的博士生。他与妻子和三个孩子(包括新生儿子 Amotz David)住在芝加哥郊外。

加载 Disqus 评论