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.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):在這一層中主要是我們服務的描述,向客戶端說明我們的服務,告訴客戶端、我們的提供了什麼樣的接口可供調用(WHAT),怎麼樣去調用(HOW),到那去調用(WHERE)。在這一層中主要的協議是WSDL(Web Services Description Language)。WSDL 是一種XML Application,它的作用就是給客戶端描述我們接口的WHAT,HOW,WHERE,也就是說:WSDL 服務定義爲分佈式系統提供了可機器識別的SDK文檔,並且可用於描述自動執行應用程序通信中所涉及的細節。
WSDL 文檔將Web服務定義爲服務訪問點或端口的集合。在 WSDL 中,由於服務訪問點和消息的抽象定義已從具體的服務部署或數據格式綁定中分離出來,因此可以對抽象定義進行再次使用:消息,指對交換數據的抽象描述;而端口類型,指操作的抽象集合。用於特定端口類型的具體協議和數據格式規範構成了可以再次使用的綁定。將Web訪問地址與可再次使用的綁定相關聯,可以定義一個端口,而端口的集合則定義爲服務。因此,WSDL 文檔在Web服務的定義中使用下列元素:
&#8226; Types - 數據類型定義的容器,它使用某種類型系統(一般地使用XML Schema中的類型系統)。
&#8226; Message - 通信消息的數據結構的抽象類型化定義。使用Types所定義的類型來定義整個消息的數據結構。
&#8226; Operation - 對服務中所支持的操作的抽象描述,一般單個Operation描述了一個訪問入口的請求/響應消息對。
&#8226; PortType - 對於某個訪問入口點類型所支持的操作的抽象集合,這些操作可以由一個或多個服務訪問點來支持。
&#8226; Binding - 特定端口類型的具體協議和數據格式規範的綁定。
&#8226; Port - 定義爲協議/數據格式綁定與具體Web訪問地址組合的單個服務訪問點。
&#8226; 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的協議,我們暫時用不上,現在也暫時沒有,以後補上(^_^) 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章