[pre]WebServices入門
——理論篇
瑞聯(lián)科技(中國)有限公司 李春林[/pre]
本文檔是用ctrl+c -> ctrl+v產(chǎn)生出來的入門級文檔,主要是想說明什么是webservices,webservices的架構(gòu),以及幾個相關(guān)的xml文檔。由于小弟知識及技術(shù)非常有限,文中不妥之處請各位兄臺指正,小弟在此謝過啦。
什么是webservices?
從表面上看:Webservices 就是一個應用程序,它向外界暴露出一個能夠通過Web進行調(diào)用的API。這就是說,你能夠用編程的方法通過Web來調(diào)用這個應用程序。我們把調(diào)用這個Webservices 的應用程序叫做客戶。
更專業(yè)的描述如下:Webservices是描述一些操作(利用標準化的 XML 消息傳遞機制可以通過網(wǎng)絡訪問這些操作)的接口。Webservices是用標準的、規(guī)范的 XML 概念描述的,稱為 Webservices的服務描述。這一描述囊括了與服務交互需要的全部細節(jié),包括消息格式(詳細描述操作)、傳輸協(xié)議和位置。該接口隱藏了實現(xiàn)服務的細節(jié),允許獨立于實現(xiàn)服務基于的硬件或軟件平臺和編寫服務所用的編程語言使用服務。這允許并支持基于 Webservices的應用程序成為松散耦合、面向組件和跨技術(shù)實現(xiàn)。Webservices履行一項特定的任務或一組任務。Webservices可以單獨或同其它 Webservices一起用于實現(xiàn)復雜的聚集或商業(yè)交易,以及企業(yè)集成(EAI)。
Webservices模型
Webservices體系結(jié)構(gòu)基于三種角色(服務提供者、服務注冊中心和服務請求者)之間的交互。交互涉及發(fā)布、查找和綁定操作。這些角色和操作一起作用于 Webservices構(gòu)件:
Webservices軟件模塊及其描述。在典型(并非 非典^_^)情況下,服務提供者托管可通過網(wǎng)絡訪問的軟件模塊(Webservices的一個實現(xiàn))。服務提供者定義 Web 服務的服務描述并把它發(fā)布到服務請求者或服務注冊中心。服務請求者使用查找操作來從本地或服務注冊中心檢索服務描述,然后使用服務描述與服務提供者進行綁定并調(diào)用 Web 服務實現(xiàn)或同它交互。服務提供者和服務請求者角色是邏輯結(jié)構(gòu),因而服務可以表現(xiàn)兩種特性。下圖 圖示了這些操作、提供這些操作的組件及它們之間的交互。
Webservices協(xié)議棧
要以一種可互操作的方式執(zhí)行發(fā)布、發(fā)現(xiàn)和綁定這三個操作,必須有一個包含每一層標準的 Webservices協(xié)議棧。下圖展示了一個概念性 Webservices協(xié)議棧。上面的幾層建立在下面幾層提供的功能之上。垂直的條表示在協(xié)議棧中每一層必須滿足的需求。左面的文本表示協(xié)議棧的那一層所應用的標準技術(shù)。
下面對上面是概念性的協(xié)議棧中,的每一層做一個粗糙的說明:
第一層(Network):這一層的這些協(xié)議都是現(xiàn)在運用比較廣泛的協(xié)議啦,現(xiàn)在HTTP運用的最多啦,好處是顯而易見的,其他的我就不多說了吧。(主要我怕我說出來會錯誤百出,被大家嘲笑。 *_*)。
第二層(XML-Based Messaging)這一層中主要體現(xiàn)怎么去調(diào)用Webservices?,F(xiàn)在運用比較廣泛的主要有兩種,一種是xml-rpc(XML-Remote Procedure Call), 另一種是SOAP(Simple Object Access Protocal)。相比之下SOAP比XML-RPC有一定的優(yōu)勢:SOAP在處理復雜數(shù)據(jù)(如數(shù)組等)要比XML-RPC更容易一些;XML-RPC沒有標準化錯誤代碼;下面我們著重看看SOAP:
什么是SOAP?
對SOAP的一種簡單理解:
SOAP是一種XML Application,SOAP簡單的理解,就是這樣的一個開放協(xié)議SOAP=RPC+HTTP+XML:采用HTTP作為底層通訊協(xié)議;RPC作為一致性的調(diào)用途徑,XML作為數(shù)據(jù)傳送的格式,允許服務提供者和服務客戶經(jīng)過防火墻在INTERNET進行通訊交互。如下圖:
對SOAP更深一步的理解:
SOAP簡單對象訪問協(xié)議是在分散或分布式的環(huán)境中交換信息的簡單的協(xié)議,是一個基于XML的協(xié)議,它包括四個部分:SOAP封裝(envelop),封裝定義了一個描述消息中的內(nèi)容是什么,是誰發(fā)送的,誰應當接受并處理它以及如何處理它們的框架,如下圖;SOAP編碼規(guī)則(encoding rules),用于表示應用程序需要使用的數(shù)據(jù)類型的實例,一般遵循XMLSchema(定義了一系列的簡單數(shù)據(jù)類型)規(guī)范; SOAP RPC表示(RPC representation),表示遠程過程調(diào)用和應答的協(xié)定;SOAP綁定(binding),使用底層協(xié)議交換信息。雖然這四個部分都作為SOAP的一部分,作為一個整體定義的,但他們在功能上是相交的、彼此獨立的。特別的,信封和編碼規(guī)則是被定義在不同的XML命名空間(namespace)中,這樣使得定義更加簡單。
圖:SOAP封裝(envelop)
下面讓我們來看一個SOAP的例子:
[pre]POST /calendar-request HTTP/1.1
Host: www.todaytech.com.cn
Content-Type: text/plain; charset="utf-8"
Content-Length: 507
SOAPAction:””
<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):在這一層中主要是我們服務的描述,向客戶端說明我們的服務,告訴客戶端、我們的提供了什么樣的接口可供調(diào)用(WHAT),怎么樣去調(diào)用(HOW),到那去調(diào)用(WHERE)。在這一層中主要的協(xié)議是WSDL(Web Services Description Language)。WSDL 是一種XML Application,它的作用就是給客戶端描述我們接口的WHAT,HOW,WHERE,也就是說:WSDL 服務定義為分布式系統(tǒng)提供了可機器識別的SDK文檔,并且可用于描述自動執(zhí)行應用程序通信中所涉及的細節(jié)。
WSDL 文檔將Web服務定義為服務訪問點或端口的集合。在 WSDL 中,由于服務訪問點和消息的抽象定義已從具體的服務部署或數(shù)據(jù)格式綁定中分離出來,因此可以對抽象定義進行再次使用:消息,指對交換數(shù)據(jù)的抽象描述;而端口類型,指操作的抽象集合。用于特定端口類型的具體協(xié)議和數(shù)據(jù)格式規(guī)范構(gòu)成了可以再次使用的綁定。將Web訪問地址與可再次使用的綁定相關(guān)聯(lián),可以定義一個端口,而端口的集合則定義為服務。因此,WSDL 文檔在Web服務的定義中使用下列元素:
• Types - 數(shù)據(jù)類型定義的容器,它使用某種類型系統(tǒng)(一般地使用XML Schema中的類型系統(tǒng))。
• Message - 通信消息的數(shù)據(jù)結(jié)構(gòu)的抽象類型化定義。使用Types所定義的類型來定義整個消息的數(shù)據(jù)結(jié)構(gòu)。
• Operation - 對服務中所支持的操作的抽象描述,一般單個Operation描述了一個訪問入口的請求/響應消息對。
• PortType - 對于某個訪問入口點類型所支持的操作的抽象集合,這些操作可以由一個或多個服務訪問點來支持。
• Binding - 特定端口類型的具體協(xié)議和數(shù)據(jù)格式規(guī)范的綁定。
• Port - 定義為協(xié)議/數(shù)據(jù)格式綁定與具體Web訪問地址組合的單個服務訪問點。
• Service - 相關(guān)服務訪問點的集合。
我們可以參考下圖,來理解一下WSDL文檔的結(jié)構(gòu)組織:
說明:其中,
Types是一個數(shù)據(jù)類型定義的容器,包含了所有在消息定義中需要的XML元素的類型定義,它一般遵循XMLSchema的規(guī)范。
Message具體定義了在通信中使用的消息的數(shù)據(jù)結(jié)構(gòu),Message元素包含了一組Part元素,每個Part元素都是最終消息的一個組成部分,每個Part都會引用一個DataType來表示它的結(jié)構(gòu)。Part元素不支持嵌套(可以使用DataType來完成這方面的需要),都是并列出現(xiàn)。
PortType具體定義了一種服務訪問入口的類型,何謂訪問入口的類型呢?就是傳入/傳出消息的模式及其格式。一個PortType可以包含若干個Operation,而一個Operation則是指訪問入口支持的一種類型的調(diào)用。在WSDL里面支持四種訪問入口調(diào)用的模式:
1. 單請求;
2. 單響應;
3. 請求/響應;
4. 響應/請求。
Service描述的是一個具體的被部署的Web服務所提供的所有訪問入口的部署細節(jié),一個Service往往會包含多個服務訪問入口,而每個訪問入口都會使用一個Port元素來描述。
Port描述的是一個服務訪問入口的部署細節(jié),包括通過哪個Web地址(URL)來訪問,應當使用怎樣的消息調(diào)用模式來訪問等。其中消息調(diào)用模式則是使用Binding結(jié)構(gòu)來表示。
Binding結(jié)構(gòu)定義了某個PortType與某一種具體的網(wǎng)絡傳輸協(xié)議或消息傳輸協(xié)議相綁定,從這一層次開始,描述的內(nèi)容就與具體服務的部署相關(guān)了。比如可以將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):這兩層都是關(guān)于UDDI的協(xié)議,我們暫時用不上,現(xiàn)在也暫時沒有,以后補上(^_^)。