开始之前
在本教程中,我们将了解 Web 服务互操作性(Web Services Interoperability,WS-Interoperability)。本教程的目标读者是构建 Web 服务,并希望确保其服务的设计能够满足最大潜在用户的使用需求的程序员。通过了解影响 Web 服务的实际互操作性问题及可以应用来避免这些问题的最佳实践,就可以区分方便用户使用的 Web 服务和充满问题的 Web 服务。
为了跟上本教程的学习,您应该具有简单对象访问协议(Simple Object Access Protocol,SOAP)和相关技术(如 WSDL)的基本知识。本教程中的示例使用了 Java™ 和 Apache Axis2 SOAP 工具包。为了更好地理解本教程,请阅读本系列中的前五篇教程,特别是第 1 部分和第 2 部分。
本系列教程以假想的报社 Daily Moon 为例;为了提高在竞争激烈的环境中的工作效率,其员工将使用各种 Web 服务来创建工作流系统,我们将在此过程中讲述各个 Web 服务基本概念。
第 1 部分比较简单,介绍了 Web 服务背后的基本概念,并演示如何使用 SOAP(以后要讨论的大部分内容的基础规范)来将 Classifieds Department 连接到内容管理系统。
第 2 部分进一步深入介绍了如何使用 Web 服务描述语言(Web Services Description Language,WSDL)定义 Web 服务产生的消息,从而使团队更方便地创建服务以及连接到服务的客户机。
在第 3 部分中,团队希望准备一系列服务,并希望能方便地查找这些服务。与此对应,统一描述、发现和集成(Universal Description, Discovery and Integration,UDDI)提供了可用服务的可搜索注册中心,以便使自己的服务为其他人所注意。
在第 4 部分中,Daily Moon 的发行人 Rudy 决定报社需要为访问其内部系统的 Web 服务制订更好的安全过程。
第 5 部分讨论了团队为了访问这些刚提供了安全保护的服务需要进行哪些更改。
第 6 部分(即本教程)将讨论如何构建和验证可互操作的 Web 服务。报社人员已经了解了获得最大可能受众的重要性,因此决定分析他们的 Web 服务,以确保任何希望使用这些服务的人员都能够方便地进行访问。
最后,第 7 部分将演示如何使用业务流程执行语言(Business Process Execution Language,WS-BPEL)来从各个服务创建复杂应用程序。
在 Web 服务系列教程的第 6 部分(也就是本教程)中,Daily Moon 的员工将进行相关工作来确保其 Web 服务具有尽可能高的互操作性。员工坚信服务将满足最初的业务需求,但并不确信是否每个人都能正常使用服务。由于存在大量的原始 SOAP 和 WSDL 规范以及需要由开发人员解释规范这一事实(会导致不兼容实现),Web 服务的互操作性问题曾经非常普遍。通过经验积累和采用 WS-I Basic Profile 中指定的最佳实践已经解决了这些问题。
对于 Daily Moon(及大部分组织)而言,压力来自于要保证组织的 Web 服务的最大流通量,以便组织进行研究,以确保 Web 服务不会出现互操作性问题。
本教程将通过动手实践的方法说明 Web 服务互操作性问题。本系列的前一部分说明了如何将 Web 服务包含到自己的软件中以及如何构建自己的服务。第 6 部分以之前的内容为基础,重点讨论如何确保所生成的 Web 服务对将使用这些服务的程序员尽可能简单和不容易出错。
本教程中使用的代码并不特定于任何编程语言或环境。所提供的示例是本系列教程中全程使用的相同示例。为了按照教程中的说明对示例进行操作,您需要安装以下软件:
Java 2 Standard Edition 的 1.4.2 或更高版本——所有这些工具都是基于 Java 的,本教程中将要构建的服务和客户机也是如此。
Apache Axis2 V1.0——Axis2 是一个功能齐全的 SOAP 工具包,提供几个 Web 服务 API 的实现,包括 SOAP 和 WSDL。Axis2 之类的工具包对于 Web 服务开发的价值是无法估量的。目前还有用于其他编程语言和环境的类似工具包。Apache 的 Axis 项目的历史悠久,源自名为 SOAP4J 的 IBM 工作项目。
Apache Geronimo 或其他应用服务器——本系列教程全程使用 Apache Geronimo J2EE 服务器(该服务器是 IBM WebSphere® Community Edition Server 的基础)。也可以使用其他应用服务器,但 Geronimo 非常简单,而且属于轻量级的免费工具,因此是快速入门非常好的选择。
概述
本教程将首先概略说明一下 Web 服务领域的现状,另外还要介绍互操作性问题及其成因。
现在程序员都在构建彼此进行通信的软件程序。每种程序语言现在都提供了能方便地以可预测方式进行网络编程的软件库。
不仅存在用于将字位从一台计算机发送到另一台计算机的底层工具,而且也有提供一组公用规则的高级协议(如 HTTP),可支持两个程序进行通信(即使由不同的人员独立构建,且部署在不同的计算机和系统软件上也能如此)。例如,想象一下当您单击 Web 浏览器中的链接并加载之前从来没有看到的网页时,将发生什么操作。通过采用一些标准(HTTP、HTML、TCP/IP),您的 Web 浏览器能够调用其他计算机系统、获取网页并将其向您呈现。这种类型的非固定的动态软件网络非常强大。Web 服务就是将此强大的功能向复杂企业系统的开发人员扩展的一个尝试。
正如 Microsoft® Internet Explorer 和 Mozilla Firefox 解释某些网页存在差异一样,在 Web 服务程序如何解释彼此交换的 SOAP 消息之间也存在差异。正如您可能想到的,这些差异可能会导致非常严重的问题,很难解决。最好的 Web 设计人员会花大量的时间和精力来了解其设计如何在不同的浏览器上工作,会像疯子一样进行大量测试,以确保其 HTML、CSS 和 Javascript 在每个浏览器上都正常工作。虽然存在规定 HTML、CSS 和 Javascript 格式的标准和规范,但这些规范并不能避免错误和模糊不清的地方。结果将导致以不同的方式解释这些规范,浏览器并不全都按照相同的方式操作。对于定义各种 Web 服务技术(如 SOAP、WSDL、UDDI、XML 模式和 HTTP)的规范也是如此。
尽管 Web 服务最初追求的是简单性,但正如本系列教程中所述,今天构建 Web 服务需要具有专门技术和耐心。现在如果要构建 Web 服务,您需要具有很好的编程背景,至少熟悉一种编程语言和环境。需要熟悉计算机网络和一系列目前 Web 服务中使用的标准技术(如 XML、SOAP、WSDL 或 XML 模式)。您还需要了解一大堆使用这些技术所需的实践技巧等等。
假如您完成了这个冗长的培训练习(可以将其称为职业经历),并尝试使用 Web 服务将您的软件连接到另一个软件,却发现无法正常工作。这会让人感觉到非常沮丧,而且这种情况会经常发生(通常在开发计划时间安排非常紧时出现)。
为了帮助对这些问题进行归类和解决,工程师团队 Web 服务互操作性组织(Web Services Interoperability Organization,WS-I)给出了针对 Web 服务开发人员的一组建议,通过遵循这些建议,就能帮助获得能良好协作的 Web 服务和 Web 服务使用者。这组建议称为 WS-I Basic Profile。如果您是 Web 服务开发人员,就应该熟悉此概要的内容。了解 Web 服务互操作性问题并主动进行恰当的服务设计来避免这些问题,这已经成为了 Web 服务开发人员的一项重要职责,就像通过设计实现跨浏览器兼容性已成为了 Web 设计人员一项重要职责一样。
并没有能够消除所有互操作性问题的万能方法。异类环境中的分布式计算是一项非常复杂的活动,肯定会出现互操作性问题。不过,通过使用规程并遵循 WS-I Basic Profile 中描述的最佳实践,其中的大部分问题都可以避免。
本系列教程逐步说明了虚构的 Daily Moon 报社的员工将其日常操作更改为基于 Web 服务的系统的过程。在第 1 部分中,Classifieds Department 通过与内容管理系统交互了解了 SOAP 的相关信息,在第 2 部分中,他们创建了自己的服务,并使用 Web 服务描述语言 (WSDL) 对其进行描述。然后,在第 3 部分,他们了解了如何与 UDDI 注册中心交互,并了解了如何在其中查找数据,而这最终使他们为自己的公司创建了一个注册中心,以支持其他组织与 Daily Moon 进行交互。在第 4 部分中,由于 Rudy 坚持要求他的同事 Gene 和 Francis 提供防止系统非授权访问的方法,因此 Gene 和 Francis 必须为其 Web 服务实现 WS-Security。在第 5 部分,Rudy 认识到需要为 Web 服务定义策略,以强制访问 Daily Moon Web 服务的客户机照预先确定的方式进行访问,确保本系列的第 4 部分中的安全性包含到其中。
互操作性概述
此部分描述用于了解互操作性问题的计划、如何测试以及一些关于 Web 服务的术语。
第一个挑战是了解互操作性问题及其在 Web 服务中的重要性。Web 服务现在使用相关技术和标准的复杂组合构建,而这正是很多互操作性问题的源头。本教程将讨论最常见的问题及其成因。
本教程将随后讨论 WS-I Basic Profile,说明其目标、语言及其详细介绍的很多可互操作 Web 服务的具体要求。
接下来,我们将和 Phil 一起检查 Daily Moon Classifieds 和 Banking Web 服务,确定可能的互操作性问题。WS-I 组织提供了一系列测试工具,可用于评估服务的互操作性。本教程将说明这些工具如何工作以及其如何支持采用测试驱动的方法构建 Web 服务。
讨论 Web 服务时,最好从提供者和使用者的角度进行描述。以下是这两个术语的常见定义:
- 使用者:使用者负责发出对提供者实现的服务的请求。
- 提供者:提供者负责侦听和处理使用者服务请求。
了解互操作性及其重要性
在此部分,本教程将详细说明互操作性问题,并说明互操作性问题的根源。我们将介绍可互操作 Web 服务的情况以及为何尝试获得最大互操作性非常重要。
我们已经了解了,Web 服务基于发送到 Web 服务提供者及从其发出的 XML 消息。另外还了解了这些消息具有一个简单的结构:信封、Header 和有效负载。在实践中,此类消息中包含的内容要多得多,经常出现这样的情况:一个程序生成 SOAP 消息并发送到另一个程序,而这个消息却令后者非常费解。程序间的这种不一致是大多数互操作性问题的根源。
即使之前已经构建过 SOAP Web 服务,您仍然可能从来没有阅读过 SOAP 和 WSDL 规范。可以使用很多工具来使用或构建 Web 服务,从而没有必要详细了解 SOAP 和 WSDL。可以通过将 WSDL 文档提供给代码生成器(如 Axis2 提供的代码生成器)来生成 Web 服务使用者和代码框架——这就帮您完成了全部繁重的工作。有时候此流程非常有效,但这些工具经常不能生成可用程序,或者即使成功了,却得到的是不能很好地与其他程序协作的存根和代码框架。
在有些动态编程语言(如 Python)中提供了动态解释 WSDL 文档的库,可以按需构建服务存根,从而能更为方便地使用 SOAP,而不必深究 SOAP 规范。这是理想的方式,但并非总能实现。
技术规范通常都很清晰明确。此类规范需要清晰,读者才能理解其讨论的具体内容。不过,尽管进行了最大的努力,SOAP 和 WSDL 规范中仍然包含一些略微混淆不清的示例和语言,迫使开发人员不得不在发现文字说明不清楚的地方尽可能自行进行判断和解释。由于软件实现所生成和预期的消息格式不同,因此会导致严重的互操作性问题。这些互操作性问题影响了 SOAP 和 Web 服务帮助程序彼此进行通信的初衷。
SOAP 是简单对象访问协议 (Simple Object Access Protocol) 的首字母缩写,此协议从第一个规范版本发布以后就存在争议,因为大部分人认为理解和使用此协议并不容易。除了模糊问题和错误外,就 Web 服务中实现互操作性而言,SOAP 规范还很复杂,而且范围非常宽泛。例如,SOAP 提供两种不同的服务类型(RPC 和 Document)和两种使用 或编码类型(Literal 和 Encoded)。服务和编码样式的选择对 Web 服务能理解的消息格式有直接影响。可以对服务和编码样式进行混合使用,从而有以下这些可能组合:
- RPC/Literal
- RPC/Encoded
- Document/Literal
- Document/Encoded
此外,Document 样式的消息可以使用称为 Wrapped 的模式,这也对所得到的消息主体有影响。对软件开发人员而言,有选择固然好,但决定使用哪个模式并不简单。关于五个可用选项间的选择有大量的讨论和混淆。WS-I Basic Profile 给出了可能组合列表,并通过建议不使用 Encoded 消息样式将此表有效地缩小了一半:
“本概要禁止使用编码,包括 SOAP 编码。
R2706 DESCRIPTION 中的 wsdl:binding 一定要使用值“literal”才能在所有 soapbind:body
、soapbind:fault
、soapbind:header
和soapbind:headerfault
元素中使用此属性。”
之所以去掉编码选项,是因为这是导致互操作性问题的一个常见原因:将其去掉可帮助缩小 Web 服务软件必须处理的消息格式的范围,而这肯定能够帮助简化和增强互操作性。
近年来,SOAP Web 服务受到了一些批评。使用 SOAP 及相关系列技术的开发人员不得不认同这是一项复杂的技术,而且互操作性挑战尤为麻烦。SOAP 无疑很强大,但简单却谈不上。事实上,从 SOAP 规范 1.2 版本 (06/2003) 以来,由于很多人抱怨这个缩写词并不准确,因此其正式称呼已不再是 SOAP 了。
目前,还有与 SOAP 竞争的其他 Web 服务类型。最值得注意的是源自代表性状态传输(Representational State Transfer,REST)的 Web 服务。REST 是一种体系结构风格,而不是特定的技术或正式标准。RESTful Web 服务顾名思义并不共享公共消息格式。其格式完全取决于服务设计人员。因此,从设计上而言,RESTful 服务也会面临与 SOAP 相同的互操作性问题。但仍然有很多用户发现 RESTful 服务的构建和使用更为简单。目前,很多组织都同时部署了这两种类型的 Web 服务,包括 amazon.com、ebay.com 和 google.com。甚至 Axis2 都包括了对 RESTful Web 服务的支持。这两种方法都具有各自的优点,将会在今后共存一段时间。
SOAP 的公共消息格式是其最重要的功能。当一切都按照预期的方式工作时,就很容易实现 SOAP 的承诺,从而也很容易理解为什么持续进行了这么多工作来通过 SOAP 实现可互操作 Web 服务。现在只需要稍加小心并进行适当的计划,就可以避免对纠缠早期 SOAP Web 服务实现的常见互操作性问题。
WS-I Basic Profile 简介
Web 服务互操作性组织(简称 WS-I)是一个行业组织,其成员包括 IBM、Microsoft、Intel®、Oracle、SAP、Hitachi 和很多其他领先企业。WS-I 的目标是“跨平台、操作系统和编程语言”努力实现 Web 服务互操作性。WS-I 是向 Web 服务开发人员提供建议的专家组,可帮助开发人员获得可互操作的 Web 服务软件。WS-I 最著名的是“Basic Profile”,其中包括一系列旨在避免互操作性问题的实现指导方针。这些指导方针实际上是一组宝贵的最佳实践。
尽管 WS-I Basic Profile 比 SOAP 和 WSDL 规范更为简洁,但仍然较为难懂。以下是一小段摘自 Basic Profile 的文本,可让您对今天的 Web 服务如何复杂有所了解:
“WSDL 1.1 对哪个模式目标名称空间适合于 WSDL 元素的 QName 引用不明确。本概要同时允许 WSDL 元素的 Qname 引用指向 xsd:schema 元素定义的目标名称空间和导入的名称空间。不允许使用对仅通过嵌套 import 定义的名称空间的QName 引用。”
Basic Profile 的大部分内容都比上述段落易懂,但务必要记住,这是一个涵盖 200 多个常见互操作性问题的技术规范,其中一些问题是由于其他技术规范中说明不清楚导致的。
SOAP、WSDL 和 WS-I Basic Profile 之类的规范主要是针对工具开发人员编写的,如 Apache 中编写 Axis2 的人员。对于构建 Web 服务的开发人员,Basic Profile 的大部分内容对其工作方式都没有直接影响,但了解 Basic Profile 中的内容也将对他们有所帮助。其中有些部分您可能会希望详细加以了解。例如,Basic Profile 包含相当多关于 WSDL 文档预期情况的信息。
Basic Profile 提供了一组指导原则,可帮助说明其目标。我们下面将给出这些原则(并进行了注解)。通过清单 1 可了解 Basic Profile 的范围和基调。
清单 1. WS-I 指导原则
|
Basic Profile 将其他规范中的松散项紧密结合在一起,但不再对其进行松散化处理。
清单 2 是 Basic Profile 的将各大规范紧密结合 的理念(如上面在 Literal 和 Encoded 示例中所示)的另一个示例。
清单 2. 更多 WS-I 指导原则
|
清单 3 中的其他原则也值得一读,因为它们可帮助确定 WS-I 的基调,应该能让您对 Basic Profile 的范围和价值有一定的认识。
清单 3. 更多 WS-I 指导原则
|
这些原则确定了 Basic Profile 的其余部分的范围和基调,讨论了作者的经验。Basic Profile 本身主要讨论互操作性,采用了务实的方法给出建议,以便能方便地加以广泛采用。
正如在上面的指导原则中间接提到的,Basic Profile 将服务划分为遵从性目标 或构件,并以此为对象提出建议。以下是其涉及的构件的完整列表:
-
MESSAGE
——传输信封的协议元素(如 SOAP 或 HTTP 消息)。 -
ENVELOPE
——soap:Envelope
元素及其内容的序列化。 -
DESCRIPTION
——类型、消息、接口及其具体协议和数据格式绑定的描述及与 Web 服务关联的网络接入点(如 WSDL 描述)。 -
INSTANCE
——实现wsdl:port
或uddi:bindingTemplate
的软件。 -
CONSUMER
——调用INSTANCE
的软件。 -
SENDER
——根据与其关联的协议生成消息的软件。 -
RECEIVER
——根据与其关联的协议使用消息的软件(如 SOAP 处理器)。 -
REGDATA
——Web 服务的注册与发现过程中涉及到的注册中心元素。(如 UDDItModels
)。
Basic Profile 的所有建议都在上面的项之一的上下文中提出的。Basic Profile 使用一组简单的限定符来说明所提出的建议的重要性。清单 4 显示了摘自 Basic Profile 的示例建议。
清单 4. 示例 WS-I 建议
|
这部分内容很容易理解。请注意,上面的每个需求都具有唯一的标识符,在对话或测试期间可以方便地供引用。这一点可能看起来有些单调,但由于它尽力保持清楚、消除含糊,Basic Profile 正式定义了其在建议中使用的数据。这些术语及其内容如清单 5 中所示。
清单 5. Basic Profile 术语
|
将 WS-I Basic Profile 与 SOAP 结合
此部分将说明具体影响 SOAP 的一些 Basic Profile 建议。这些建议尝试阐明可能存在的与 SOAP 信封、错误和 HTTP 使用相关的互操作性问题。
SOAP 指定基于在信封 中传递的 XML 消息的协议。Basic Profile 要求遵循此规范的 Web 服务按照 SOAP 规范中的定义使用此模式,并增加了有关其使用的约束。以下将对 Basic Profile 所施加的约束进行简要总结。此列表并不完整,但有助于您了解 Basic Profile 的广度和范围。
- 概要中要求信封符合 SOAP 1.1 中规定的结构。 这似乎有些像废话,但这也清楚地说明了 SOAP 1.1 消息传递是该概要所支持的唯一消息传递格式。
- 信封一定不能包含文档类型声明(Document Type Declaration,DTD)或处理说明 (Processing Instruction)。概要将这些内容作为安全缺陷、处理开销和语义模糊的原因加以引用。此外,信封还不应包含 XML 名称空间声明
xmlns:xml="http://www.w3.org/XML/1998/namespace
和xmlns:xml="http://www.w3.org/XML/1998/namespace
。 - 在信封中,一定不能存在任何 body 元素的同级元素。概要指出,此类同级元素的解释不够清楚,因此概要不允许使用这些内容。这就正式确定了 SOAP 消息是具有单个主体且包含有效负载的信封。
- 正如前面提到的,概要禁止使用
soap:encodingStyle
属性,从而取消了编码 SOAP 消息。这是一项非常重要的建议,因为已经对此主题进行了大量讨论,而很多互操作性问题都源于使用了编码 XML 消息。
Basic Profile 将各个细节与 SOAP 错误信封进行了紧密结合:
- 概要首先定义错误是包含单个
soap:Body
子元素(其中包含单个子元素soap:Fault
)的信封。其他任何内容都不会解释为错误。 - 不应使用 HTTP 状态代码来确定是否存在错误。而应通过解释 SOAP 消息来确定是否存在错误。
- 当信封是错误时,其中仅允许存在子元素
faultcode
、faultstring
、faultactor
和 detail。一定不能对这些元素进行名称空间限定。 - 为了保持可扩展性,Basic Profile 规定 SOAP 错误在 detail 元素中可以包含任意数量的子元素。
同样,以上这些只是部分重要内容而已。大部分此类建议并不会直接影响 Web 服务创建者,但在遇到互操作性问题时一定要加以注意。
由于 HTTP 是最常用且最受欢迎的 SOAP 消息传输协议,而且 Basic Profile 选择使用其作为使用 Web 服务的绑定,并推荐了一些额外的最佳实践做法,因此适用以下这些内容:
- 必须使用 HTTP 1.0 或 HTTP 1.1 发送消息,但首选 HTTP 1.1 且应该尽可能加以使用。
- HTTP 请求消息必须使用 HTTP POST 方法,一定不能使用 HTTP 扩展框架(HTTP Extension Framework,SOAP 1.1 中允许使用此框架)。
- 应该使用 HTTP 2XX 状态代码指示 HTTP 请求的成功输出。当响应消息包含的不是错误的信封时,应该使用状态代码
200
。当没有从 HTTP 请求返回 SOAP 信封时,200
或202
应表示成功输出。 - 随请求消息使用的 HTTP Header 中的 SOAPAction 字段必须为带英文引号的字符串:这看起来似乎是个小细节,但对 WSDL 会有影响;WSDL 应与以下所示之一类似:
-
<soapbind:operation soapAction="someAction" />
。这将得到请求SOAPAction="someAction"
的 HTTP Header。 -
<soapbind:operation soapAction="" />
。这将得到请求SOAPAction=""
的 HTTP Header。 -
<soapbind:operation />
。这也将得到请求SOAPAction=""
的 HTTP Header。
-
了解 WS-I Basic Profile 和 WSDL 的关系
Basic Profile 的服务描述建议部分首先要求在收到请求时将服务提供者的 WSDL 提供给 Web 服务使用者。这强调了 WSDL 作为 Web 服务契约的重要性,可帮助形成有益于临时使用 Web 服务的 Web 服务环境。还应该始终能够在注册中心中找到服务、请求其 WSDL、解释 WSDL 并使用服务。
Basic Profile 要求以有效的 XML 1.0 版编写服务描述。不过并不强制要求使用 WSDL 或 XML 模式规范的特定版本。Basic Profile 正式确定了这一点,可帮助提高互操作性。
Basic Profile 对 WSDL import 语句进行了限制,将其限制为仅在所导入的文档是 WSDL 文档时使用。这是另一个重要的要求,因为 WSDL 1.1 规范中有一个示例错误地将 WSDL import 语句用于导入 XML 模式定义,此要求就是针对此示例而提出的。概要对 XML 模式导入也有类似的限制,指定只能将其用于导入 XML 模式定义。
将 WSDL 文档导入另一个 WSDL 文档中时,Basic Profile 要求这两个 WSDL 文档位于相同的名称空间中(所导入的 WSDL 的wsdl:definitions
上的 targetNamespace
属性应具有与执行导入操作的 WSDL 中的 wsdl:import 元素上的 namespace 属性相同的值)。这实际上就是将导入限制为将其置入已经在父名称空间中定义的项中,而不允许进行名称空间强制操作。
Basic Profile 建议 WSDL 文档中的项以特定顺序出现。WSDL import 元素必须位于除 wsdl:documentation
之外的 WSDL 名称空间的所有其他元素之前。WSDL 类型元素必须位于除 wsdl:documentation
和 wsdl:import
之外的 WSDL 名称空间的所有其他元素之前。除了 WSDL 1.1 指定的元素之外,还可以将 WSDL documentation 元素作为 wsdl:import
、wsdl:part
和 wsdl:definition
的第一个元素出现。
概要对使用 WSDL 扩展提出了警告,因为这些扩展很可能会导致互操作性问题。
Basic Profile 取消了 WSDL 数组类型,因为存在多种不同的解释方法。应该避免使用 Wsdl:arrayType
和 soapenc:ArrayType
。不建议使用 ArrayOfXXX
数组命名约定。应该转而使用清单 6 中所示的序列声明数组。
清单 6. 符合 Basic Profile 要求的数组定义
|
Basic Profile 不允许在 wsdl:portType
中使用名称重载。这意味着每个操作的 name 属性都必须具有明确的值。
描述中的 wsdl:binding
必须为 RPC-Literal 绑定或 Document-Literal 绑定。 本教程中已经对此进行了多次复述,因为它对消息格式有重要的影响。
描述中的 wsdl:binding
必须为所有 soapbind:body
、soapbind:fault, soapbind:header
和 soapbind:headerfault
元素中的 use
属性使用“literal”值。
正如您看到的,Basic Profile 提出了很多影响 WSDL 的建议。WSDL 是 Web 服务中使用的一个非常重要的规范。在本部分中给出的 Basic Profile WSDL 建议是最可能对您产生影响的建议。这些建议都是针对 Web 服务的最常见 WSDL 相关互操作性问题。
了解 WS-I Basic Profile 使用方案
在一个独立于 Basic Profile 之外的文档中,WS-I 定义了三个使用方案,对访问 Web 服务时的三个常见模式进行了描述。使用方案文档说明了这三个使用方案如何工作以及如何使用 Web 服务中提供的构件(如 WSDL)实现。
以下使用方案的重要特点之一是,它们是可组合的,这意味着可以将其作为构建块来创建更为复杂的使用方案。
当 Web 服务使用者需要向服务提供者发送消息,而使用者并不要求保证消息正确交付或处理,则可使用单向使用方案。当然,每次都会尝试交付并处理消息。但在出现问题的情况下,由于此使用方案存在以下特征,因此无法告知使用者关于错误的消息:
- 提供者不会提供 SOAP 响应消息(也不预期存在此消息)。
- 并不要求基础传输保证将消息交付给提供者。
为什么会希望使用这些具有重大注意事项的系统呢?在有些情况下,不能成功交付的消息可能并不会带来灾难性的结果,如将消息发送到应用程序日志时。单向方案在这种情况下是非常不错的选择,因为它是一种轻量级方法。此方法还可对系统的可伸缩性起到促进作用,因为使用者并不需要等待请求被处理或为接收提供者发出的任何响应而做准备。系统可以继续进行其他事情,不受其限制。
使用方案文档详细说明了如何在 WSDL 中使用单向使用方案。根据使用的是 Document/Literal 绑定还是 RPC/Literal 绑定(Basic Profile 只允许采用这两种绑定类型),会略微有所不同。所有这些使用方案均以 Basic Profile 为基础制定。它们对符合 Basic Profile 要求的技术进行了说明。
无论如何,单向方案都要求将单个输入消息发送到提供者,而不指定输出消息。
同步请求/响应是 Web 服务和所有分布式计算中最常用的使用模式。这个使用方案是我们非常习惯的一种方法,因为它正确描述了我们在现实世界中遇到的很多情况。例如,当停下来询问到最近的咖啡店怎么走时,您需要进行以下工作:
- 找到看起来能够帮您的人。
- 询问其是否知道到附近的咖啡店怎么走。
- 等待其思考并回答您的问题。
- 在对方告诉您答案时听对方讲话。
如果您向人问路然后不等他回答就走开(就像采用单向使用方案一样),这样做并没有什么意义。在此示例中,非常重要的是,要等待接收方处理您向其提供的信息并形成您能够使用的响应。
在同步请求/响应方案中,服务将接收 SOAP 请求消息,并生成客户机焦急等待的 SOAP 响应消息。
如果使用者希望从提供者接收结果,但使用者并不希望等待结果,就可以使用基本回调方案。例如,如果使用者要求提供者形成一个复杂的报告,而这个报告需要大量的处理时间才能完成,则可以使用此方案。使用者不必等待报告,而只需向提供者提供足够的信息,以便其知道在准备好结果后如何通知使用者。
基本回调是通过组合使用两个异步回调使用方案来实现的,由使用者向提供者发出初始请求,而这将导致提供者最终将最后的响应发送回使用者。清单 7 给出了 WS-I 对基本回调方案的描述。
清单 7. 基本回调使用方案
|
这些使用方案并未由任何 Web 服务标准指定,仅仅是 Web 服务和使用这些服务的应用程序所使用的常见通信模式。将这些方案归类(正如 WS-I 所做的)非常重要,因为这些方案可就如何实现可互操作的服务为开发人员提供建议。有关更多信息,请阅读使用方案文档(请参见参考资料中给出的链接)。您将在其中看到 WS-I 所定义的用于实现这三个使用模式的 WSDL 定义示例。
使用 WS-I 测试工具
WS-I Basic Profile 的作者希望让遵循其提出的要求的工作变得非常简单。他们知道,大部分开发人员宁愿将精力放在构建软件上,而不愿意阅读另一个枯燥的技术文档。考虑到这一点,他们创建了一组测试工具,可供开发人员用于检查各种 Web 服务构件是否符合 Basic Profile 的要求。这个策略非常好,因为大部分 Web 服务开发人员都希望知道自己的服务符合标准(因而尽可能消除了互操作性问题),然后继续后面的工作。虽然我们很喜欢从互操作性专家的专业知识获得好处,但我们大多数人对成为互操作性专家都不感兴趣。
您可以直接从 WS-I 下载一套工具来使用。这个套件中包括用于截取 Web 服务接收和发出的消息的 Monitor 工具和用于检查各个 Web 服务构件(包括使用 Monitor 截取的消息)的 Analyzer 工具。
接下来让我们回到 Daily Moon 和 Phil 身上,他们需要考虑的是报社的新 Web 服务的互操作性。Phil 花了大量的时间研究互操作性方面的知识,他发现了 WS-I,大略地阅读了 Basic Profile 并下载了 WS-I 测试工具。
WS-I 测试工具中包括一个监视应用程序,能够截取 Web 服务提供者和使用者间的通信内容。这是通过中间人 来实现的,这样使用者与 Monitor 应用程序通信,而后者在不做任何修改的情况下将请求转发到提供者。Monitor 将提供者发回的所有响应转发给使用者,同时也不会以任何方式对其进行修改。Monitor 将记录看到的所有内容。它可以看到 SOAP 消息和 HTTP 流:这是 Web 服务的两个重要组成部分,可供稍后进行分析来确定互操作性问题。
Monitor 应用程序使用 XML 配置文件。WS-I 测试工具套件中提供了一个示例 Monitor 配置文件,对于 Java 版本套件,该文件位于 $WSI_HOME/java/samples/monitorConfig.xml。Phil 首先将此示例文件复制到自己的本地工作区,并对其进行编辑,以指定用于存储日志的位置。他决定创建两个独立的配置:一个用于 Classified Advertisement 服务,一个用于 Banking 服务。所得到的日志文件非常重要,因为稍后将使用另一个测试工具对其进行分析。
Monitor 配置文件还指定用于侦听使用者请求的端口和将请求发送到提供者所使用的端口。提供者端口相当标准。对于大多数系统而言,缺省侦听端口应该是安全可用的。检查了这些端口号后,Phil 决定采用缺省设置。
Phil 确保测试服务在运行后,使用提供的批处理文件 (Monitor.bat) 和为 Classified Advertisement 服务创建的配置文件启动 Monitor。清单 8 显示了启动 Monitor 工具得到的输出。
清单 8. 启动 Monitor 工具
|
接下来,Phil 需要更改其测试用例,以使其使用替代服务 URL,以便 Monitor 能截取每个使用者的消息并将其转发到正在运行的服务实例。通过更改每个测试,使其构造具有显式服务 URL 的测试存根来覆盖用于创建测试用例的 WSDL 中包括的 URL,即可非常方便地完成此工作。
对于 Classified 服务的测试,这意味着要创建清单 9 中所示的存根,从而使用端口 4040 替代在端口 8080 上与服务提供者进行的直接通信。
清单 9. 构造用于进行测试的 ClassifiedServiceStub
|
接下来,Phil 为 Classified Advertisement 服务运行每个测试用例。成功后所得的结果如清单 10 中所示。
清单 10. 运行 ClassifiedServiceTest
|
运行了这些测试后,Phil 注意到,随着 Monitor 应用程序截取从使用者和提供者发出的请求和响应的增加,其日志条目也急剧增加。所生成的日志条目如清单 11 中所示。
清单 11. Monitor 日志条目
|
现在监视工作已经完成,Phil 已准备好运行 Analyzer 来查找互操作性问题。
Analyzer 测试工具也使用 XML 配置文件。同样,Phil 首先复制 WS-I 测试套件中的示例文件。对于 Java 套件,该示例文件位于 $WSI_HOME/java/samples/analyzerConfig.xml。Phil 复制了两个副本:一个副本用于 Classified Advertisements 服务,另一个副本用于 Banking 服务。
Analyzer 程序能够处理 Monitor 创建的日志文件,以寻找用于进行分析的消息。另外还能够分析 WSDL 文档和其他构件。
Phil 针对此服务对示例配置进行了编辑,添加了对其服务 WSDL 的引用。所得到的配置文件如清单 12 中所示。
清单 12. Analyzer 配置文件中经过更新的 WSDL 引用
|
Phil 然后确保 Analyzer 的配置知道您的监视会话生成的日志文件的正确位置。他选择将 log.xml 记录到当前目录中。此更改如清单 13 中所示。
清单 13. Analyzer 配置文件中经过更新的日志文件位置
|
此时,Phil 所需要做的就是运行 Analyzer,如清单 14 中所示。
清单 14. 运行 Analyzer 工具
|
Phil 对 Classified Advertisement 服务重复了此过程。Analyzer 中最有意义的输出是其生成的报告。该报告是 XML 文件,可以在任何支持 XSLT 的任意浏览器中查看,如 Internet Explorer 或 Firefox。
Analyzer 的报告给出了关于其分析的每个 Web 服务总体是否通过的评估。另外,它还提供了 Basic Profile 要求的详细列表,并逐条给出是否通过的评估。Phil 首先加载的 Banking 服务的 Analyzer 的报告,发现其中有一项失败,如图 1 中所示。
图 1. 显示未通过的 Analyzer 工具报告
不幸的是,似乎是此服务违反了一条或多条 Basic Profile 要求。Analyzer 对其的评估是未通过。通过分析细节,Phil 发现一个 Banking 服务的 WSDL 描述未能满足的要求。该报告还提供了一些细节,如图 2 中所示。
图 2. 详细 Analyzer 报告
仔细查看此信息几次并仔细研读 Banking 服务的 WSDL 后,Phil 认识到问题一定在于清单 15 中所示 soap:body 元素中包含的名称空间。
清单 15. soap:body 中指定的带名称空间的输入定义
|
他删除了此 WSDL 中的每个输入中的名称空间定义,使其与清单 16 中所示类似,希望这将使 Analyzer 工具通过其服务。
清单 16. 不带名称空间的 soap:body
|
他随后再次运行 Analyzer 工具,重新在浏览器中加载报告,发现服务现在完全符合 WS-I Basic Profile 的要求了。Phil 非常幸运,他所做的是一个相当简单的更改。
Phil 认识到他更改了 Banking 服务的 WSDL 描述。现在必须确保 WSDL 仍然能正确地与 Axis2 工具包一起工作。为此,他使用 WSDL2Java 命令重新生成了服务框架和客户机存根类,进行编译并再次进行测试。幸运的是,一切都正常,而且能够确保 Banking Web 服务没有 Basic Profile 中描述的互操作性问题。
Phil 对 Classified Advertising Web 服务重复了整个过程,也遇到了类似的情况。服务由于 BP2019 而未能通过。他对此服务进行了相同的调整,并随后通过了所有测试。
WS-I 的测试工具极为有用,使得遵循 Basic Profile 的最佳实践的工作变得非常容易。如果碰巧使用的是 Eclipse,还可以选择使用其他工具来测试 Basic Profile 的遵循情况。Eclipse Web Tools Project 为 Eclipse 提供了各种有用的增强功能,包括用于编辑 WSDL 和 XML 模式文件的特殊编辑器、很多常见 Web 编程文件格式的语法突出显示以及可以用于分析 WSDL 文档来确定是否符合 Basic Profile 要求的一组测试工具。尽管 WS-I 提供的测试工具在其质量和范围方面给人印象深刻,不过仍然有很多人发现 Eclipse Web Tools Project 提供的工具更为适合自己的工作流。
拥有一套工具,就能以测试驱动的方式验证您的服务。通过将这些测试集成到开发环境中,可以进一步提高此流程的效率。图 3 显示了一个示例 Eclipse Web Tools 插件。该工具突出显示了上面 Phil 在 Analyzer 测试时所遇到的相同 Basic Profile 建议,但这次是在 Eclipse 中完成的,直接在问题所在位置显示。
图 3. 突出显示错误的 Eclipse Web Tools 插件
现在 Phil 已经验证其服务通过了 Basic Profile 遵从性测试,他决定让潜在用户拥有足够的信心,确信已经进行了所有工作来避免互操作性问题。Basic Profile 描述了如何进行这样的声明。Phil 按照示例中的方式将 wsi:Claim
元素添加到其 WSDL 文档中的端口定义,如清单 17 中所示。
清单 17. WSDL 端口的 Basic Profile 遵从性声明示例
|
总结
本教程介绍了 Web 服务互操作性的概念,并提供了一组简单的推荐做法,在避免互操作性问题的过程中可以通过采用这些做法来利用强大的专家专业知识。互操作性是一个重要的问题,是每个 Web 服务开发人员都应该考虑的问题。我们在本教程中了解了 WS-I Basic Profile 和可以对服务运行以确保不会存在常见互操作性问题的自动化测试。