WebServices入门 [pre]WebServices入门 ——理论篇 瑞联科技(中国)有限公司 李春林[/pre]本文档是用ctrl+c -> ctrl+v产生出来的入门级文档,主要是想说明什么是webservices,webservices的架构,以及几个相关的xml文档。由于小弟知识及技术非常有限,文中不妥之处请各位兄台指正,小弟在此谢过啦。什么是webservices? 从表面上看:Webservices 就是一个应用程序,它向外界暴露出一个能够通过Web进行调用的API。这就是说,你能够用编程的方法通过Web来调用这个应用程序。我们把调用这个Webservices 的应用程序叫做客户。更专业的描述如下:Webservices是描述一些操作(利用标准化的 XML 消息传递机制可以通过网络访问这些操作)的接口。Webservices是用标准的、规范的 XML 概念描述的,称为 Webservices的服务描述。这一描述囊括了与服务交互需要的全部细节,包括消息格式(详细描述操作)、传输协议和位置。该接口隐藏了实现服务的细节,允许独立于实现服务基于的硬件或软件平台和编写服务所用的编程语言使用服务。这允许并支持基于 Webservices的应用程序成为松散耦合、面向组件和跨技术实现。Webservices履行一项特定的任务或一组任务。Webservices可以单独或同其它 Webservices一起用于实现复杂的聚集或商业交易,以及企业集成(EAI)。Webservices模型Webservices体系结构基于三种角色(服务提供者、服务注册中心和服务请求者)之间的交互。交互涉及发布、查找和绑定操作。这些角色和操作一起作用于 Webservices构件:Webservices软件模块及其描述。在典型(并非 非典^_^)情况下,服务提供者托管可通过网络访问的软件模块(Webservices的一个实现)。服务提供者定义 Web 服务的服务描述并把它发布到服务请求者或服务注册中心。服务请求者使用查找操作来从本地或服务注册中心检索服务描述,然后使用服务描述与服务提供者进行绑定并调用 Web 服务实现或同它交互。服务提供者和服务请求者角色是逻辑结构,因而服务可以表现两种特性。下图 图示了这些操作、提供这些操作的组件及它们之间的交互。 Webservices协议栈要以一种可互操作的方式执行发布、发现和绑定这三个操作,必须有一个包含每一层标准的 Webservices协议栈。下图展示了一个概念性 Webservices协议栈。上面的几层建立在下面几层提供的功能之上。垂直的条表示在协议栈中每一层必须满足的需求。左面的文本表示协议栈的那一层所应用的标准技术。 下面对上面是概念性的协议栈中,的每一层做一个粗糙的说明:第一层(Network):这一层的这些协议都是现在运用比较广泛的协议啦,现在HTTP运用的最多啦,好处是显而易见的,其他的我就不多说了吧。(主要我怕我说出来会错误百出,被大家嘲笑。 *_*)。第二层(XML-Based Messaging)这一层中主要体现怎么去调用Webservices。现在运用比较广泛的主要有两种,一种是xml-rpc(XML-Remote Procedure Call), 另一种是SOAP(Simple Object Access Protocal)。相比之下SOAP比XML-RPC有一定的优势:SOAP在处理复杂数据(如数组等)要比XML-RPC更容易一些;XML-RPC没有标准化错误代码;下面我们着重看看SOAP:什么是SOAP? 对SOAP的一种简单理解:SOAP是一种XML Application,SOAP简单的理解,就是这样的一个开放协议SOAP=RPC+HTTP+XML:采用HTTP作为底层通讯协议;RPC作为一致性的调用途径,XML作为数据传送的格式,允许服务提供者和服务客户经过防火墙在INTERNET进行通讯交互。如下图: 对SOAP更深一步的理解:SOAP简单对象访问协议是在分散或分布式的环境中交换信息的简单的协议,是一个基于XML的协议,它包括四个部分:SOAP封装(envelop),封装定义了一个描述消息中的内容是什么,是谁发送的,谁应当接受并处理它以及如何处理它们的框架,如下图;SOAP编码规则(encoding rules),用于表示应用程序需要使用的数据类型的实例,一般遵循XMLSchema(定义了一系列的简单数据类型)规范; SOAP RPC表示(RPC representation),表示远程过程调用和应答的协定;SOAP绑定(binding),使用底层协议交换信息。虽然这四个部分都作为SOAP的一部分,作为一个整体定义的,但他们在功能上是相交的、彼此独立的。特别的,信封和编码规则是被定义在不同的XML命名空间(namespace)中,这样使得定义更加简单。 图:SOAP封装(envelop)下面让我们来看一个SOAP的例子:[pre]POST /calendar-request HTTP/1.1Host: www.todaytech.com.cnContent-Type: text/plain; charset="utf-8"Content-Length: 507SOAPAction:””<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <ns1:searchPaynoteResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://external.charge.gfmis.todaytech.com"> <searchPaynoteReturn href="#id0"/> </ns1:searchPaynoteResponse> <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:ExternalPaynoteVO" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="http://vo.charge.gfmis.todaytech.com"> <paynoteNO xsi:type="xsd:string">0300000003004</paynoteNO> <startDate xsi:type="xsd:string" xsi:nil="true"/> <disaID xsi:type="xsd:string" xsi:nil="true"/> <annotation xsi:type="xsd:string" xsi:nil="true"/> <chargeItemNO3 xsi:type="xsd:string" xsi:nil="true"/> <amount xsi:type="xsd:double">0.0</amount> <chargeItemNO2 xsi:type="xsd:string" xsi:nil="true"/> <loginKey xsi:type="xsd:string">YCpTEwKEw</loginKey> <chargeItemNO1 xsi:type="xsd:string" xsi:nil="true"/> <userSign xsi:type="xsd:string" xsi:nil="true"/> <operator xsi:type="xsd:string" xsi:nil="true"/> <userCert xsi:type="xsd:string" xsi:nil="true"/> <quantity3 xsi:type="xsd:double">0.0</quantity3> <quantity2 xsi:type="xsd:double">0.0</quantity2> <unitName xsi:type="xsd:string" xsi:nil="true"/> <srvSign xsi:type="xsd:string" xsi:nil="true"/> <quantity1 xsi:type="xsd:double">0.0</quantity1> <srvCert xsi:type="xsd:string" xsi:nil="true"/> <externalPaynoteNO xsi:type="xsd:string" xsi:nil="true"/> <status xsi:type="xsd:int">1</status> <randStr xsi:type="xsd:string" xsi:nil="true"/> <returnCode xsi:type="xsd:int">0</returnCode> <endDate xsi:type="xsd:string" xsi:nil="true"/> <price3 xsi:type="xsd:double">0.0</price3> <price2 xsi:type="xsd:double">0.0</price2> <price1 xsi:type="xsd:double">0.0</price1> <unitNO xsi:type="xsd:string" xsi:nil="true"/> <payerName xsi:type="xsd:string" xsi:nil="true"/> </multiRef> </soapenv:Body></soapenv:Envelope>[/pre]第三层(Service Description):在这一层中主要是我们服务的描述,向客户端说明我们的服务,告诉客户端、我们的提供了什么样的接口可供调用(WHAT),怎么样去调用(HOW),到那去调用(WHERE)。在这一层中主要的协议是WSDL(Web Services Description Language)。WSDL 是一种XML Application,它的作用就是给客户端描述我们接口的WHAT,HOW,WHERE,也就是说:WSDL 服务定义为分布式系统提供了可机器识别的SDK文档,并且可用于描述自动执行应用程序通信中所涉及的细节。 WSDL 文档将Web服务定义为服务访问点或端口的集合。在 WSDL 中,由于服务访问点和消息的抽象定义已从具体的服务部署或数据格式绑定中分离出来,因此可以对抽象定义进行再次使用:消息,指对交换数据的抽象描述;而端口类型,指操作的抽象集合。用于特定端口类型的具体协议和数据格式规范构成了可以再次使用的绑定。将Web访问地址与可再次使用的绑定相关联,可以定义一个端口,而端口的集合则定义为服务。因此,WSDL 文档在Web服务的定义中使用下列元素:• Types - 数据类型定义的容器,它使用某种类型系统(一般地使用XML Schema中的类型系统)。 • Message - 通信消息的数据结构的抽象类型化定义。使用Types所定义的类型来定义整个消息的数据结构。 • Operation - 对服务中所支持的操作的抽象描述,一般单个Operation描述了一个访问入口的请求/响应消息对。 • PortType - 对于某个访问入口点类型所支持的操作的抽象集合,这些操作可以由一个或多个服务访问点来支持。 • Binding - 特定端口类型的具体协议和数据格式规范的绑定。 • Port - 定义为协议/数据格式绑定与具体Web访问地址组合的单个服务访问点。 • Service - 相关服务访问点的集合。 我们可以参考下图,来理解一下WSDL文档的结构组织:说明:其中, Types是一个数据类型定义的容器,包含了所有在消息定义中需要的XML元素的类型定义,它一般遵循XMLSchema的规范。Message具体定义了在通信中使用的消息的数据结构,Message元素包含了一组Part元素,每个Part元素都是最终消息的一个组成部分,每个Part都会引用一个DataType来表示它的结构。Part元素不支持嵌套(可以使用DataType来完成这方面的需要),都是并列出现。PortType具体定义了一种服务访问入口的类型,何谓访问入口的类型呢?就是传入/传出消息的模式及其格式。一个PortType可以包含若干个Operation,而一个Operation则是指访问入口支持的一种类型的调用。在WSDL里面支持四种访问入口调用的模式:1. 单请求; 2. 单响应; 3. 请求/响应; 4. 响应/请求。 Service描述的是一个具体的被部署的Web服务所提供的所有访问入口的部署细节,一个Service往往会包含多个服务访问入口,而每个访问入口都会使用一个Port元素来描述。Port描述的是一个服务访问入口的部署细节,包括通过哪个Web地址(URL)来访问,应当使用怎样的消息调用模式来访问等。其中消息调用模式则是使用Binding结构来表示。Binding结构定义了某个PortType与某一种具体的网络传输协议或消息传输协议相绑定,从这一层次开始,描述的内容就与具体服务的部署相关了。比如可以将PortType与SOAP/HTTP绑定,也可以将PortType与MIME/SMTP相绑定等。 下面我们给出一个WSDL的文档实例:[pre]<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions targetNamespace="http://external.charge.gfmis.todaytech.com" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://external.charge.gfmis.todaytech.com-impl" xmlns:intf="http://external.charge.gfmis.todaytech.com" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns2="http://vo.charge.gfmis.todaytech.com" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <wsdl:types> <schema targetNamespace="http://vo.charge.gfmis.todaytech.com" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> <complexType name="ExternalPaynoteVO"> <sequence> <element name="amount" type="xsd:double"/> <element name="annotation" nillable="true" type="xsd:string"/> <element name="chargeItemNO1" nillable="true" type="xsd:string"/> <element name="chargeItemNO2" nillable="true" type="xsd:string"/> <element name="chargeItemNO3" nillable="true" type="xsd:string"/> <element name="disaID" nillable="true" type="xsd:string"/> <element name="endDate" nillable="true" type="xsd:string"/> <element name="externalPaynoteNO" nillable="true" type="xsd:string"/> <element name="loginKey" nillable="true" type="xsd:string"/> <element name="operator" nillable="true" type="xsd:string"/> <element name="payerName" nillable="true" type="xsd:string"/> <element name="paynoteNO" nillable="true" type="xsd:string"/> <element name="price1" type="xsd:double"/> <element name="price2" type="xsd:double"/> <element name="price3" type="xsd:double"/> <element name="quantity1" type="xsd:double"/> <element name="quantity2" type="xsd:double"/> <element name="quantity3" type="xsd:double"/> <element name="randStr" nillable="true" type="xsd:string"/> <element name="returnCode" type="xsd:int"/> <element name="srvCert" nillable="true" type="xsd:string"/> <element name="srvSign" nillable="true" type="xsd:string"/> <element name="startDate" nillable="true" type="xsd:string"/> <element name="status" type="xsd:int"/> <element name="unitNO" nillable="true" type="xsd:string"/> <element name="unitName" nillable="true" type="xsd:string"/> <element name="userCert" nillable="true" type="xsd:string"/> <element name="userSign" nillable="true" type="xsd:string"/> </sequence> </complexType> <element name="ExternalPaynoteVO" nillable="true" type="tns2:ExternalPaynoteVO"/> </schema> </wsdl:types> <wsdl:message name="logoutRequest"> <wsdl:part name="epnvo" type="tns2:ExternalPaynoteVO"/> </wsdl:message> <wsdl:message name="searchPaynoteResponse"> <wsdl:part name="searchPaynoteReturn" type="tns2:ExternalPaynoteVO"/> </wsdl:message> <wsdl:message name="searchPaynoteRequest"> <wsdl:part name="epnvo" type="tns2:ExternalPaynoteVO"/> </wsdl:message> <wsdl:message name="genPaynoteResponse"> <wsdl:part name="genPaynoteReturn" type="tns2:ExternalPaynoteVO"/> </wsdl:message> <wsdl:message name="loginResponse"> <wsdl:part name="loginReturn" type="tns2:ExternalPaynoteVO"/> </wsdl:message> <wsdl:message name="logoutResponse"> <wsdl:part name="logoutReturn" type="tns2:ExternalPaynoteVO"/> </wsdl:message> <wsdl:message name="genPaynoteRequest"> <wsdl:part name="epvo" type="tns2:ExternalPaynoteVO"/> </wsdl:message> <wsdl:message name="loginRequest"> <wsdl:part name="epnvo" type="tns2:ExternalPaynoteVO"/> </wsdl:message> <wsdl:portType name="ExternalInterface"> <wsdl:operation name="login" parameterOrder="epnvo"> <wsdl:input message="intf:loginRequest" name="loginRequest"/> <wsdl:output message="intf:loginResponse" name="loginResponse"/> </wsdl:operation> <wsdl:operation name="logout" parameterOrder="epnvo"> <wsdl:input message="intf:logoutRequest" name="logoutRequest"/> <wsdl:output message="intf:logoutResponse" name="logoutResponse"/> </wsdl:operation> <wsdl:operation name="genPaynote" parameterOrder="epvo"> <wsdl:input message="intf:genPaynoteRequest" name="genPaynoteRequest"/> <wsdl:output message="intf:genPaynoteResponse" name="genPaynoteResponse"/> </wsdl:operation> <wsdl:operation name="searchPaynote" parameterOrder="epnvo"> <wsdl:input message="intf:searchPaynoteRequest" name="searchPaynoteRequest"/> <wsdl:output message="intf:searchPaynoteResponse" name="searchPaynoteResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="ExternalInterfaceSoapBinding" type="intf:ExternalInterface"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="login"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="loginRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://external.charge.gfmis.todaytech.com" use="encoded"/> </wsdl:input> <wsdl:output name="loginResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://external.charge.gfmis.todaytech.com" use="encoded"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="logout"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="logoutRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://external.charge.gfmis.todaytech.com" use="encoded"/> </wsdl:input> <wsdl:output name="logoutResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://external.charge.gfmis.todaytech.com" use="encoded"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="genPaynote"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="genPaynoteRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://external.charge.gfmis.todaytech.com" use="encoded"/> </wsdl:input> <wsdl:output name="genPaynoteResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://external.charge.gfmis.todaytech.com" use="encoded"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="searchPaynote"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="searchPaynoteRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://external.charge.gfmis.todaytech.com" use="encoded"/> </wsdl:input> <wsdl:output name="searchPaynoteResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://external.charge.gfmis.todaytech.com" use="encoded"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="ExternalInterfaceService"> <wsdl:port binding="intf:ExternalInterfaceSoapBinding" name="ExternalInterface"> <wsdlsoap:address location="http://localhost:7001/gfmis/services/ExternalInterface"/> </wsdl:port> </wsdl:service></wsdl:definitions>[/pre]第四层(Service Publication):第五层(Service Discovery):这两层都是关于UDDI的协议,我们暂时用不上,现在也暂时没有,以后补上(^_^)。