WSDL: 描述你的 Web 服务
柴晓路
2001-8-13
本文最初由 IBM developerWorks 中国网站发表,其网址是
http://www.ibm.com/developerWorks/cn/
Web Service “Stack”
在我的先前的文章中,我已经介绍过 Web 服务的整个技术体系 Web Service “stack” ,如下图:
** ??? **
|
** ??? **
|
** Management **
|
** Quality of Service **
|
** Security **
---|---|---|---|---
** Routing, Reliability and Transaction **
|
** ??? **
** Workflow **
|
** WSFL **
** Service Discovery, Integration **
|
** UDDI **
** Service Description **
|
** WSDL **
** Messaging **
|
** SOAP **
** Transport **
|
** HTTP, FTP, SMTP **
** Internet **
|
** IPv4, IPv6 **
其中,绿色部分是先前已经定义好的并且广泛使用的传输层和网络层的标准: IP 、 HTTP 、 SMTP 等。而蓝色部分是目前开发的 Web 服务的相关标准协议,包括服务调用协议 SOAP 、服务描述协议 WSDL 和服务发现 / 集成协议 UDDI ,以及服务工作流描述语言 WSFL 。而橙色部分描述的是更高层的待开发的关于路由、可靠性以及事务等方面的协议。黄色部分是各个协议层的公用机制,这些机制一般由外部的正交机制来完成。
其中,一个可以使用的 Web 服务应当按照需要选用若干层次的功能,而无需所有的特性。但是无论如何为了实现一个一般意义上的 Web 服务,具备 Web 服务的基础特性:跨平台调用和接口可机器识别,那么必需使用 WSDL 和 SOAP 。 SOAP 是用来最终完成 Web 服务调用的,而 WSDL 则是用于描述如何使用 SOAP 来调用 Web 服务的。
WSDL 是一种 XML Application ,他将 Web 服务描述定义为一组服务访问点,客户端可以通过这些服务访问点对包含面向文档信息或面向过程调用的服务进行访问 ( 类似远程过程调用 ) 。 WSDL 首先对访问的操作和访问时使用的请求 / 响应消息进行抽象描述,然后将其绑定到具体的传输协议和消息格式上以最终定义具体部署的服务访问点。相关的具体部署的服务访问点通过组合就成为抽象的 Web 服务。
在具体使用中,我们可以对 WSDL 进行扩展 ( 类似 SOAP 的可扩展性 ) ,这样无论通信时使用何种消息格式或网络协议,都可以对服务访问点及其使用的消息格式进行描述。在 WSDL 的框架中,可以使用任意的消息格式和网络协议,如同 SOAP 中可以使用任意的网络协议一样。在 WSDL 规范中,定义了如何使用 SOAP 消息格式、 HTTP GET/POST 消息格式以及 MIME 格式来完成 Web 服务交互的规范。
WSDL 概述
由于通信协议和消息格式在 Web 技术圈子里已经达到了标准化,我们知道在通常的开发过程中,对于对象的 Interface 一定具备相应的 SDK 描述文档, Web 服务也是一种对象,只不过它是被部署在 Web 上而已。很自然的,我们也完全需要有对 Web 服务这个对象的界面的 SDK 描述文档。然而这两者又不尽相同,一来目前在 Web 上的应用已经完全接受了 XML 这个基本的标准,基本上所有新出台的技术都是基于 XML 标准的,二来 Web 服务的目标是即时装配,松散耦合以及自动集成的,这意味着 SDK 描述文档应当是具备被机器识别的能力的。
也就是说,对于使用标准化的消息格式 / 通信协议的 Web 服务,它需要以某种结构化的方式 ( 即 XML) 对 Web 服务的调用 / 通信加以描述,而且实现这一点也显得非常重要,这是 Web 服务即时装配的基本保证。 WSDL 正是这样一种描述语言, WSDL 定义了一套基于 XML 的 语法,将 Web 服务描述为能够进行消息交换的服务访问点的集合,从而满足了这种需求。 WSDL 服务定义为分布式系统提供了可机器识别的 SDK 文档,并且可用于描述自动执行应用程序通信中所涉及的细节。
WSDL 文档将 Web 服务定义为服务访问点或端口的集合。在 WSDL 中,由于服务访问点和消息的抽象定义已从具体的服务部署或数据格式绑定中分离出来,因此可以对抽象定义进行再次使用:消息,指对交换数据的抽象描述;而端口类型,指操作的抽象集合。用于特定端口类型的具体协议和数据格式规范构成了可以再次使用的绑定。将 Web 访问地址与可再次使用的绑定相关联,可以定义一个端口,而端口的集合则定义为服务。因此, WSDL 文档在 Web 服务的定义中使用下列元素:
Ÿ Types - 数据类型定义的容器,它使用某种类型系统 ( 一般地使用 XML Schema 中的类型系统 ) 。
Ÿ Message – 通信消息的数据结构的抽象类型化定义。使用 Types 所定义的类型来定义整个消息的数据结构。
Ÿ Operation - 对服务中所支持的操作的抽象描述,一般单个 Operation 描述了一个访问入口的请求 / 响应消息对。
Ÿ Port Type – 对于某个访问入口点类型所支持的操作的抽象集合,这些操作可以由一个或多个服务访问点来支持。
Ÿ Binding - 特定端口类型的具体协议和数据格式规范的绑定。
Ÿ Port - 定义为协议 / 数据格式绑定与具体 Web 访问地址组合的单个服务访问点。
Ÿ Service - 相关服务访问点的集合。
大家可以参考下图,来理解一下 WSDL 文档的结构组织:
其中, Types 是一个数据类型定义的容器,包含了所有在消息定义中需要的 XML 元素的类型定义,我将在今后的文章中结合 XML Schema 来详细说明如何进行类型定义。
Message 具体定义了在通信中使用的消息的数据结构, Message 元素包含了一组 Part 元素,每个 Part 元素都是最终消息的一个组成部分,每个 Part 都会引用一个 DataType 来表示它的结构。 Part 元素不支持嵌套 ( 可以使用 DataType 来完成这方面的需要 ) ,都是并列出现。
PortType 具体定义了一种服务访问入口的类型,何谓访问入口的类型呢?就是传入 / 传出消息的模式及其格式。一个 PortType 可以包含若干个 Operation ,而一个 Operation 则是指访问入口支持的一种类型的调用。在 WSDL 里面支持四种访问入口调用的模式: 1) 单请求 ; 2) 单响应 ; 3) 请求 / 响应 ; 4) 响应 / 请求。在这里请求指的是从客户端到 Web 服务端,而响应指的是从 Web 服务端到客户端。 PortType 的定义中会引用消息定义部分的一个到两个消息,作为请求或响应消息的格式。比如,一个股票查询的访问入口可能就会支持两种请求消息,一种请求消息中指明股票代码,而另一种请求消息中则会指明股票的名称,响应消息可能都是股票的价格等等。
以上三种结构描述了调用 Web 服务的抽象定义,这三部分与具体 Web 服务部署细节无关,是可复用的描述 ( 每个层次都可以复用 ) 。如果与一般的对象语言做比较的话,这部分可以堪称是 IDL 描述的对象,描述了对象的接口标准,但是到底对象是用哪种语言实现,遵从哪种平台的细节规范,被部署在哪台机器上则是后面的元素所描述的。
Service 描述的是一个具体的被部署的 Web 服务所提供的所有访问入口的部署细节,一个 Service 往往会包含多个服务访问入口,而每个访问入口都会使用一个 Port 元素来描述。
Port 描述的是一个服务访问入口的部署细节,包括通过哪个 Web 地址 (URL) 来访问,应当使用怎样的消息调用模式来访问等。其中消息调用模式则是使用 Binding 结构来表示。
Binding 结构定义了某个 PortType 与某一种具体的网络传输协议或消息传输协议相绑定,从这一层次开始,描述的内容就与具体服务的部署相关了。比如可以将 PortType 与 SOAP/HTTP 绑定,也可以将 PortType 与 MIME/SMTP 相绑定等。
在介绍了 WSDL 的主要元素之后,大家会发现, WSDL 的设计理念完全继承了以 XML 为基础的当代 Web 技术标准的一贯设计理念:开放。 WSDL 允许通过扩展使用其他的类型定义语言 ( 不光是 XML Schema) ,允许使用多种网络传输协议和消息格式 ( 不光是在规范中定义的这些: SOAP/HTTP , HTTP-GET/POST 以及 MIME 等 ) 。同时 WSDL 也应用了当代软件工程中的复用理念,分离了抽象定义层和具体部署层,使得抽象定义层的复用性大大增加。比如我们可以先使用抽象定义层为一类 Web 服务进行抽象定义 ( 比如 UDDI Registry ,抽象定义肯定是完全一致的遵循了 UDDI 规范 ) ,而不同的运营公司可以采用不同的具体部署层的描述结合抽象定义完成其自身的 Web 服务的描述。
WSDL 文档示例
下例是一个提供股票报价的简单 Web 服务的 WSDL 定义。该服务支持名为 GetLastTradePrice 的单一操作,这个操作是通过在 HTTP 上运行 SOAP 1.1 协议来实现的。该请求接受一个类型为字符串的 tickerSymbol ,并返回类型为浮点数的价格。
1<definitions name="StockQuote" targetnamespace="http://andsky.com/stockquote.wsdl" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://andsky.com/stockquote.wsdl" xmlns:xsd1="http://andsky.com/stockquote.xsd">
2<types>
3<schema targetnamespace="http://andsky.com/stockquote.xsd" xmlns="http://www.w3.org/1999/XMLSchema">
4<element name="TradePriceRequest">
5<complextype>
6<all>
7<element name="tickerSymbol" type="string"></element>
8</all>
9</complextype>
10</element>
11<element name="TradePriceResult">
12<complextype>
13<all>
14<element name="price" type="float"></element>
15</all>
16</complextype>
17</element>
18</schema>
19</types>
20
21上面这部分是数据类型的定义,其中为定义了两个元素的结构 :
22
23Ÿ TradePriceRequest( 交易价格请求 ): 将该元素定义为包含一个字符串元素 (tickerSymbol) 的复合类型元素。
24
25Ÿ TradePriceResult( 交易价格 ): 将该元素定义为一个包含一个浮点数元素 (price) 的复合类型元素。
26
27<message name="GetLastTradePriceInput">
28<part element="xsd1:TradePriceRequest" name="body"></part>
29</message>
30<message name="GetLastTradePriceOutput">
31<part element="xsd1:TradePriceResult" name="body"></part>
32</message>
33
34这部分是消息格式的抽象定义,其中定义了两个消息格式:
35
36Ÿ GetlastTradePriceInput( 获取最后交易价格的请求消息格式 ): 由一个消息片断组成,该消息片断的名字是 body ,包含的具体元素类型是 TradePriceRequest 。 ( 前面已经定义过了 )
37
38Ÿ GetLastTradePriceOutput( 获取最后交易价格的响应消息格式 ) : 由一个消息片断组成,该消息片断的名字是 body ,包含的具体元素类型是 TradePriceResult 。 ( 前面已经定义过了 )
39
40<porttype name="StockQuotePortType">
41<operation name="GetLastTradePrice">
42<input message="tns:GetLastTradePriceInput"/>
43<output message="tns:GetLastTradePriceOutput"></output>
44</operation>
45</porttype>
46
47这部分定义了服务访问点的调用模式的类型,表明 StockQuoteService 的某个入口类型是请求 / 响应模式,请求消息是 GetlastTradePriceInput ,而响应消息是 GetLastTradePriceOutput 。
48
49<binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">
50<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"></soap:binding>
51<operation name="GetLastTradePrice">
52<soap:operation soapaction="http://andsky.com/GetLastTradePrice"></soap:operation>
53<input/>
54<soap:body encodingstyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://andsky.com/stockquote.xsd" use="literal"></soap:body>
55<output>
56
57<soap:body use="literal"
58
59namespace="http://andsky.com/stockquote.xsd"
60
61<P class=Para style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 42pt; mso-line-height-alt: 0pt; ms</output></operation></binding></definitions>