解析Web接口描述语言WSDL
一、概述
Web服务定义语言(Web Services Definition Language,WSDL)是一个建议性标准,用于描 述Web服务的技术调用语法。WSDL定义了一套基于 XML的语法,将Web服务描述为能够进行消息交换的服务访问点的集合,从而满足了这种需求。WSDL服务定义为分布式系统提供了可机器识别的SDK文档,并且可用于描述自动执行应用程序通信中所涉及的细节。WSDL的当前版本是1.1,规范可以从http://www.w3.org/TR/wsdl获得。
WSDL就是描述XMLWeb服务的标准XML格式,WSDL由Ariba、Intel、IBM和微软等开发商提出。它用一种和具体语言无关的抽象方式定义了给定Web服务收发的有关操作和消息。就其定义来说,你还不能把WSDL当作一种对象接 口定义语言,例如,CORBA或COM等应用程序体系结构就会用到对象接口定义语言。 WSDL保持协议中立,但它确实内建了绑定SOAP的支持,从而同SOAP建立了不可分割的联系。
WSDL服务描述是一个XML文档,它与WSDL模式(schema)的定义一致。WSDL文档并不是完整的服务描述,而只包括了服务描述任务的较低层次,即:服务接口的原始技术描述。WSDL是Web服务的接口定义语言IDL(Interface Definition Language,),本质上,WSDL描述说明的是Web服务的以下三个基本属性:
服务做些什么--服务所提供的操作(方法)。
如何访问服务--数据格式详情以及访问服务操作的必要协议。
服务位于何处--由特定协议决定的网络地址,如URL。
二、WSDL文档结构
WSDL文档将Web服务定义为服务访问点或端口的集合。在 WSDL中,由于服务访问点和消息的抽象定义已从具体的服务部署或数据格式绑定中分离出来,因此可以对抽象定义进行再次使用:消息,指对交换数据的抽象描述;端口类型指操作的抽象集合。用于特定端口类型的具体协议和数据格式规范构成了可以再次使用的绑定。将Web访问地址与可再次使用的绑定相关联,可以定义一个端口,而端口的集合则定义为服务。
1、WSDL信息模型
WSDL信息模型充分利用了抽象规范与规范具体实现的分离,也就是分离了服务接口定义(抽象接口)与服务实现定义(具体端点)。 抽象接口规范描述了终端的处理能力,它在WSDL中表示为portType。束定机制 (binding mechanism)在WSDL中表示为binding元素,它使用特定的通信协议、数据编码模型和底层通信协议,将Web服务的抽象定义映射至特定实现。若束定结合了实现的访问地址,抽象端点也就成为可供服务请求者调用的具体端点(concrete endpoint),WSDL的port元素表示了这一结合。
抽象接口可以支持任何数量的操作(operations)。操作是由一组消息(messages)定义,消息定义了操作的交互定式。与抽象的消息、操作概念相对应的具体实现是由binding元素指定。与XML应用相同,WSDL模式定义了几个高层元素,或称为主要元素。在WSDL中,Web服务描述中的主要元素如下:
Types,定义了Web服务使用的所有数据类型集合,可被元素的各消息部件所引用。它使用某种类型系统(一般地使用XMLSchema中的类型系统)。
Message,通信消息数据结构的抽象类型化定义。使用Types所定义的类型来定义整个消息的数据结构。
Operation,对服务中所支持操作的抽象描述。一般单个Operation描述了一个访问入口的请求/响应消息对。
PortType,对于某个访问入口点类型所支持操作的抽象集合。这些操作可以由一个或多个服务访问点来支持。
Binding,包含了如何将抽象接口的元素(portType)转变为具体表示的细节,具体表示也就是指特定的数据格式和协议的结合;特定端口类型的具体协议和数据格式规范的绑定。
Port,定义为协议/数据格式绑定与具体Web访问地址组合的单个服务访问点。
Service,这是一个粗糙命名的元素,代表端口的集合;相关服务访问点的集合。
因此,portType(与message和type元素的细节相结合)描述了Web服务是什么,binding元素描述了如何使用Web服务,port及service元素描述了Web服务的位置。
图1 WSDL信息模型
图1体现了WSDL信息模型的一个可能结构,它清楚反映了portType元素包含的抽象消息/操作和binding元素的具体消息/操作间的关系。图中的黑体字突出了WSDL规范中的术语。WSDL使用的元素名称有些含糊,由于不存在能够区分抽象和具体概念的一致命名原则,因此必须记住哪一个元素代表抽象概念,哪一个元素代表具体的概念。
2、WSDL对象结构图
从图2所示的WSDL对象结构图可知,一个WSDL文档中可以包含一个Types,多个Message、PortType、Binding和Service。
图2 WSDL对象结构图
其中,Types是一个数据类型定义的容器,包含了所有在消息定义中需要的XML元素的类型定义。
Message具体定义了在通信中使用的消息的数据结构,Message元素包含了一组Part元素,每个Part元素都是最终消息的一个组成部分,每个Part都会引用一个DataType来表示它的结构。Part元素不支持嵌套(可以使用DataType来完成这方面的需要),都是并列出现。
PortType具体定义了一种服务访问入口的类型(传入/传出消息的模式及其格式),一个PortType可以包含若干个Operation,而一个Operation则是指访问入口支持的一种类型的调用。在WSDL里面支持四种访问入口调用的模式:1) 单请求; 2) 单响应; 3) 请求/响应; 4) 响应/请求。在这里请求指的是从客户端到Web服务端,而响应指的是从Web服务端到客户端。PortType的定义中会引用消息定义部分的一个到两个消息,作为请求或响应消息的格式。
Service描述的是一个具体的被部署的Web服务所提供的所有访问入口的部署细节,一个Service往往会包含多个服务访问入口,而每个访问入口都会使用一个Port元素来描述。
Port描述的是一个服务访问入口的部署细节,包括通过哪个Web地址(URL)来访问,应当使用怎样的消息调用模式来访问等。其中消息调用模式则是使用Binding结构来表示。
Binding结构定义了某个PortType与某一种具体的网络传输协议或消息传输协议相绑定,从这一层次开始,描述的内容就与具体服务的部署相关了。比如可以将PortType与SOAP/HTTP绑定,也可以将PortType与MIME/SMTP相绑定等。
3、WSDL文档类型
WSDL文档被分为两种类型:服务接口(service interface )和服务实现(service implementations)。(如下图3所示)
图3 WSDL文档类型
服务接口由 WSDL文档来描述,这种文档包含服务接口的 types、import、message、portType 和 binding 等元素。服务接口包含将用于实现一个或多个服务的 WSDL服务定义。它是 Web 服务的抽象定义,并被用于描述某种特定类型的服务。
通过使用一个 import 元素,一个服务接口文档可以引用另一个服务接口文档。例如,一个仅包含 message 和 portType 元素的服务接口可以被另一个仅包含此 portType 的绑定的服务接口引用。
WSDL服务实现文档将包含 import 和 service 元素。服务实现文档包含实现一个服务接口的服务的描述。import 元素中至少会有一个将包含对 WSDL服务接口文档的引用。一个服务实现文档可以包含对多个服务接口文档的引用。
WSDL服务实现文档中的 import 元素包含两个属性。namespace 的属性值是一个与服务接口文档中的 targetNamespace 相匹配的URL。location 属性是一个用于引用包含完整的服务接口定义的 WSDL文档的 URL。port 元素的 binding 属性包含对服务接口文档中的某个特定绑定的引用。
服务接口文档由服务接口提供者开发和发布。服务实现文档由服务提供者创建和发布。服务接口提供者与服务提供者这两个角色在逻辑上是分离的,但他们可以是同一个商业实体。
一个完整的 WSDL服务描述是由一个服务接口和一个服务实现文档组成的。
4、WSDL工具
你可以手工创建WSDL文件,不过,你还可以采用相当多的工具通过WSDL来为你自动处理和定义Web服务。推荐工具软件如下:
Omniopera----图形用户界面的WSDI、XML和XSD编辑器。
Microsoft的SOAP Toolkit----一种工具包,其中包括根据WSDL定义创建COM接口的向导程序,还包括根据COM接口创建WSDL的向导程序。
IBM的Web Services Toolkit----一种工具包,其中包括产生WSDL和SOAP部署说明的向导程序。
三、WSDL扩展机制
WSDL设计继承了以XML为基础的当代Web技术标准的开放设计理念。它允许通过扩展使用其它的类型定义语言(不光是XMI Schema),允许使用多种网络传输协议和消息格式(不仅是在规范中定义的SOAP/HTTP、HTTP-GET/POST及MIME等)。WSDL也应用了当代软件工程中的复用理念,分离了抽象定义层和具体部署层,使得抽象定义层的复用性大大增加。
1、 SOAP绑定
WSDL包括用于SOAP 1.1终端的绑定,此绑定支持下列协议信息规范:
需要指示出此绑定是针对SOAP 1.1协议的。
为SOAP 终端指定地址的方式。
用于SOAPAction HTTP头的URI,而此头是绑定了SOAP 的HTTP头。
作为SOAP封装一部分传送的头列表定义。
SOAP绑定使用下列扩展元素对WSDL进行扩展:(注意黑体标注)
<definitions .... >
<binding .... >
<soap:binding style="rpc|document" transport="uri"> …1
<operation .... >
<soap:operation soapAction="uri" style="rpc|document"> …2
<input>
<soap:body parts="nmtokens" use="litera |encoded"
encodingStyle="uri-list" namespace="uri">…3
<soap:header message="qname" fault="qname"/> …4
</input>
<output>
<soap:body parts="nmtokens" use="litera |encoded"
encodingStyle="uri-list"? namespace="uri"/>…3
<soap:header message="qname" fault="qname"/> …4
</output>
<fault>
<soap:fault name="nmtoken" use="litera |encoded"
encodingStyle="uri-list" namespace="uri">…5
</fault>
</operation>
</binding>
<port .... >
<soap:address location="uri"/> …6
</port>
</definitions>
1)soap:binding
SOAP绑定元素的目的是指出绑定是针对SOAP协议格式的:Envelope, Header 和 Body。这个元素没有对编码或消息格式进行声明。在使用SOAP绑定时必须指出soap:binding元素。
2)soap:operation
soap:operation 元素从整体上为操作提供信息。
style属性指出操作是面向RPC(消息包含参数和返回值)的还是面向文档的(消息包含文档)。此信息可用于选择合适的编程模板。此属性的值将影响SOAP消息体的构建方式,如果没有指定值,它默认为soap:binding元素中指定的值。如果soap:binding元素没有指定样式,它假定为"文档"。
soapAction属性为此操作的SOAPAction头指定了值。此URI应当被直接用作SOAPAction头的值,在作出请求时不要试图将一个相对URI变成绝对URI。对于绑定了SOAP的HTTP协议来说,此值是必需的(它没有默认值)。对于其它的SOAP协议绑定,决对不能为其指定值,而soap:operation元素可以被忽略。
3)soap:body
soap:body元素指出了消息部分应如何在SOAP Body元素中表现。
消息的各个部分可以是抽象的类型定义,也可以是具体的模式定义。如果是抽象定义,根据编码格式定义的一套规则将对类型进行序列化。使用URI列表可以对每种编码格式进行标识,就象在SOAP规范中的那样。由于某些编码格式如SOAP编码允许某种给定的抽象类型的消息格式发生变化,那么读者应理解所有的格式变化:"读者决定正确性"。为了避免对所有变化不必要的支持,可以对消息的定义具体化,然后暗示它的原始编码格式(如果存在)。在这种情况下,消息的创建者必须严格遵循特定的规范:"作者决定正确性"。
soap:body提供的信息用于决定如何在SOAP消息的Body元素中组合不同的消息部分。soap:body元素可以用在面向RPC的消息也可以用在面向文档的消息中,但是封装操作的格式对Body节如何构建有重要影响:
如果操作格式是RPC,那么每个部分将是一个参数,或者是一个返回值,并且它们出现在body中的wrapper元素内。wrapper元素的名字与操作的名字相同,并且它的名称空间是namespace属性的值。每个消息部分(参数)在封装器下出现,它是由与调用中相应参数名称相同的存储器表示的。各部分以与调用参数相同的顺序进行排列。
如果操作格式是文档,那么就没有额外的封装器(wrappers),消息的parts直接出现在SOAP Body元素中。
在定义Body的内容和参数存储器元素时使用了相同的机制。
4)soap:header
soap:header元素允许在SOAP封装的头元素中对将要传送的头进行定义。它模拟了soap:body元素。并不需要使用soap:header费力地列出出现在SOAP封装中的所有头元素。例如,对WSDL的扩展暗示特定的头应加入到实际的有效负荷中,此时就不需要列出所有的头。
5)soap:fault
soap:fault元素指出了SOAP Fault Details元素的内容,它模仿了soap:body元素。
6)soap:address
SOAP地址绑定用于为端口指定地址。使用SOAP绑定的端口必须指定一个确切的地址,为地址指定的URI配制必须与soap:binding指定的传输相对应。
2、 HTTP GET 与 POST 绑定
为了描述Web浏览器与网站间的交互作用,WSDL包含了HTTP 1.1的 GET 和 POST版本的绑定。这种绑定允许应用程序而不浏览器与网站进行交互。可以指定下面的协议特定信息:
使用了HTTP GET 或 POST绑定的标记
端口地址
每种操作的相对地址(相对于端口定义的基地址)
HTTP GET/POST绑定使用下列元素扩展WSDL:(注意黑体标注)
<definitions .... >
<binding .... >
<http:binding verb="nmtoken"/>…1
<operation .... >
<http:operation location="uri"/>…2
<input .... >
<-- mime elements -->
</input>
<output .... >
<-- mime elements -->
</output>
</operation>
</binding>
<port .... >
<http:address location="uri"/>…3
</port>
</definitions>
1)http:binding
http:binding元素指出此绑定使用了HTTP协议。必需的Verb属性的值指出了HTTP的版本,其值通常是GET或POST,但也可以使用其它值。注意,HTTP版本是大小写敏感的。
2)http:operation
Location属性为操作指定一个相对URI,此URI与http:address元素指定的URI结合在一起形成了HTTP请求的完整路径。此URI必须是一个相对的URI。
3)http:address
location属性为端口指定了基地址。其值是与http:operation绑定元素的位置(location)属性的值结合在一起的。
4)http:urlEncoded
UrlEncoded元素指出所有的消息part都按照标准的URI编码规则(名字=值…)编码进HTTP请求URI中。参数名与消息part的名相对应。使用"名字=值"对对part提供的值进行编码。通常使用GET指示URL编码,或使用POST指示一个FORM-POST。对于GET,字符"?"作为必需,将自动追加。
<http:urlEncoded/>
5)http:urlReplacement
http:urlReplacement元素指出所有的消息part都使用替代运算法则被编码进HTTP请求URI中:
http:operation 的相对URI值用于搜索一组探索方案。
在http:operation的值与http:address的位置属性的值结合前开始搜索。
每个消息part有一个搜索方式。搜索方式字符串是附加了"("和")"的消息part 的名字。对每个匹配,相应消息part的值在匹配处替代匹配。
匹配检查在任何值被替代前执行(已经替代的值不会引发另外的匹配检查)。
消息part不能有重复值。
<http:urlReplacement/>
3、 MIME 绑定
WSDL包含了以某种MIME格式将抽象类型与具体消息绑定在一起的方式。为下列MIME类型定义了绑定:
multipart/related
text/XML
application/x-www-form-urlencoded (此格式用于替代HTML中的表单)
其它 ( 由MIME类型字符串指定)
对MIME类型的定义的工作量很大,且是发展的,因此为每种MIME类型费力地定义XML语法不是WSDL的目标。在需要时,不排除增加额外的语法以定义另外的MIME类型。如果MIME类型字符串提供的信息足够描述内容,那么就可以使用下面定义的mime元素。
MIME绑定使用下列元素扩展WSDL:(注意黑体标注)
<mime:content part="nmtoken"? type="string"?/>…1
<mime:multipartRelated>…2
<mime:part> * …3
<-- mime element -->
</mime:part>
</mime:multipartRelated>
<mime:mimeXMLpart="nmtoken"?/> …4
1)mime:content
为了避免为每个MIME格式定义新的元素,如果不需要传送格式(而不是MIME类型字符串)的附加信息,就可以使用mime:content元素。
<mime:content part="nmtoken"? type="string"?/>
属性part用于指定消息part的名字。如果只有一个part,那么它的属性是可选的。属性type包含MIME类型的字符串。类型的值是由斜杠(/),每个值可以是一个通配符(*)。如果没有指定类型属性,就表示所有的MIME类型是可选的。
如果返回格式是XML,但模式事先并不知道,通用mime元素可用于指示text/XML:
<mime:content type="text/XML"/>
通配符可用于指定某类MIME类型,对所有文本类型如下例所示:
<mime:content type="text/*"/>
下面两个例子都指定了所有的mime类型:
<mime:content type="*/*"/>
<mime:content/>
2)mime:multipartRelated
multipart/related MIME类型任意的MIME格式化部分聚集为一个使用MIME 类型"multipart/related"的消息。
3)mime:part
元素mime:part描述了multipart/related消息的各个部分。在mime:part元素中出现的MIME元素用于为各部分指定具体的MIME类型。如果在一个mime:part元素中出现多个MIME元素,那么它们是可相互替换的。
4)mime:mimeXML为了指定与SOAP不兼容(没有SOAP封装)的XML负荷,但存在一个特殊的模式,就可以使用mime:mimeXml元素指定具体的模式。属性part引用定义了根XML元素具体模式的消息part。如果消息只有一个part,那么就可以忽略part属性。part使用element属性为单个part引用具体模式,或者使用type 属性为组合part进行引用。
5)soap:body
当SOAP请求使用MIME绑定时,将元素soap:body作为MIME元素使用是合法的。这指出内容的类型是"text/XML",并且存在SOAP封装。