由于通信協定和消息格式在 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描述了一個通路入口的請求/響應消息對。
porttype - 對于某個通路入口點類型所支援的操作的抽象集合,這些操作可以由一個或多個服務通路點來支援。
binding - 特定端口類型的具體協定和資料格式規範的綁定。
port - 定義為協定/資料格式綁定與具體web通路位址組合的單個服務通路點。
service - 相關服務通路點的集合。
大家可以參考下圖,來了解一下wsdl文檔的結構組織:

其中,types是一個資料類型定義的容器,包含了所有在消息定義中需要的xml元素的類型定義,我将在今後的文章中結合xml schema來詳細說明如何進行類型定義。
porttype具體定義了一種服務通路入口的類型,何謂通路入口的類型呢?就是傳入/傳出消息的模式及其格式。一個 porttype可以包含若幹個operation,而一個operation則是指通路入口支援的一種類型的調用。在wsdl裡面支援四種通路入口調用的模式:
one-way 此操作可接受消息,但不會傳回響應。
request-response 此操作可接受一個請求并會傳回一個響應
solicit-response 此操作可發送一個請求,并會等待一個響應。
notification 此操作可發送一條消息,但不會等待響應。
一個 one-way 操作的例子:
<message name="newtermvalues">
<part name="term" type="xs:string"/>
<part name="value" type="xs:string"/>
</message>
<porttype name="glossaryterms">
<operation name="setterm">
<input name="newterm" message="newtermvalues"/>
</operation>
</porttype >
在這個例子中,端口 "glossaryterms" 定義了一個名為 "setterm" 的 one-way 操作。
這個 "setterm" 操作可接受新術語表項目消息的輸入,這些消息使用一條名為 "newtermvalues" 的消息,此消息帶有輸入參數 "term" 和 "value"。不過,沒有為這個操作定義任何輸出。僞代碼相當于:
function setterm(string term, string value){
...
return null;
}
一個 request-response 操作的例子:
<message name="gettermrequest">
<message name="gettermresponse">
<operation name="getterm">
<input message="gettermrequest"/>
<output message="gettermresponse"/>
</operation>
</porttype>
在這個例子中,<porttype> 元素把 "glossaryterms" 定義為某個端口的名稱,把 "getterm" 定義為某個操作的名稱。
操作 "getterm" 擁有一個名為 "gettermrequest" 的輸入消息,以及一個名為 "gettermresponse" 的輸出消息。
<message> 元素可定義每個消息的部件,以及相關聯的資料類型。
對比傳統的程式設計,glossaryterms 是一個函數庫,而 "getterm" 是帶有輸入參數 "gettermrequest" 和傳回參數 gettermresponse 的一個函數。
namespace的作用是要避免命名沖突。如果我建立一項web service,其中的wsdl檔案包含一個名為"foo"的元素,而你想要使用我的服務與另一項服務連接配接作為補充,這樣的話另一項服務的wsdl檔案就 不能包含名為"foo"的元素。兩個伺服器程式隻有在它們在兩個事例中表示完全相同的東西時,才可以取相同的名字。如果有了表示差別的 namespace,我的網絡服務裡的"foo"就可以表示完全不同于另一個網絡服務裡"foo"的含義。在你的用戶端裡,你隻要加以限制就可以引用我 的"foo"。
見下例:http://www.infotects.com/fooservice#foo 就是完全限制的名字,相當于"carlos:foo",如果我聲明了carlos作為http://www.infotects.com /fooservice的快捷方式。請注意namespace中的url是用來确定它們的唯一性的,同時也便于定位。url所指向的地方不必是實際存在的 網絡位址,也可以使用guid來代替或補充url。例如,guid"335db901-d44a-11d4-a96e-0080ad76435d"就是一 個合法的namespace指派。
<?xml version = "1.0" encoding = "utf-8"?>
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
<service name="helloservice" targetnamespace="urn:star" typenamespace="urn:star" packagename="helloservice">
<interface name="helloservice.helloif"/>
</service>
</configuration>
name =”helloservice” 服務名稱:helloservice
targetnamespace=”urn:star” wsdl名字空間:urn:star
<interface name=”helloservice.helloif”/> 服務的端點(endpoint)接口:helloservice.helloif
uri、url和urn是識别、定位和命名網際網路上的資源的标準途徑; url,urn是uri的子集.
uri不能定位或讀取/寫入資源。這是統一的資源定位器(url)的任務。url是一種uri,但是它的大綱元件是已知的網絡協定(簡稱協定),并且它把uri元件與某種協定處理程式(一種資源定位器和根據協定建立的限制規則與資源通訊的讀/寫機制)。
uri一般不能為資源提供持久不便的名稱。這是統一的資源命名(urn)的任務。urn也是一種uri,但是全球唯一的、持久不便的,即使資源不在存在或不再使用。
web上位址的基本形式是uri,它代表統一資源辨別符。有兩種形式:
url:目前uri的最普遍形式就是無處不在的url或統一資源定位器。
urn:url的一種更新形式,統一資源名稱(urn, uniform resource name)不依賴于位置 ,并且有可能減少失效連接配接的個數。但是其流行還需假以時日,因為它需要更精密軟體的支援。
體系中的uri、url和urn是彼此關聯的。uri的範疇位于體系的頂層,url和urn的範疇位于體系的底層。這種排列顯示url和urn都是uri的子範疇, uri表示的是統一的資源辨別,它是以某種統一的(标準化的)方式辨別資源的簡單字元串。
按照 uri 标準,上面的第一個例子 —— http://www.cisco.com/en/us/partners/index.html —— 實際上是一個 uri,并且它由以下幾個組成部分:
方案名 (<code>http</code> )
域名 (<code>www.cisco.com</code> )
路徑 (<code>/en/us/partners/index.html</code> )
其中的一些例子有:
<code>mailto:mbox@domain</code>
<code>ftp://host/file</code>
<code>http://domain/path</code>
<span><definitions name="travelapprove"
targetnamespace="http://eclipse.org/bpel/travel"
xmlns:tns="http://eclipse.org/bpel/travel"
xmlns:plnk="http://docs.oasis-open.org/wsbpel/2.0/plnktype"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
></span>
這句話也定義一個"travelapprove" 屬于http://eclipse.org/bpel/travel命名空間!
<porttype name="stockquoteporttype">
<operation name="getlasttradeprice">
<input message="tns:getlasttradepriceinput"/>
<output message="tns:getlasttradepriceoutput"/>
</operation>
</porttype>
這部分定義了服務通路點的調用模式的類型,表明stockquoteservice的某個入口類型是請求/響應模式,請求消息是getlasttradepriceinput,而響應消息是getlasttradepriceoutput。
<binding name="stockquotesoapbinding" type="tns:stockquoteporttype">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getlasttradeprice">
<soap:operation soapaction="http://example.com/getlasttradeprice"/>
<input>
<soap:body use="literal" namespace="http://example.com/stockquote.xsd"
encodingstyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
</output>
</soap:operation>
</operation>
</soap:binding>
</binding>
這部分将服務通路點的抽象定義與soap http綁定,描述如何通過soap/http來通路按照前面描述的通路入口點類型部署的通路入口。其中規定了在具體soap調用時,應當使用的 soapaction是"http://example.com/getlasttradeprice",而請求/響應消息的編碼風格都應當采用soap 規範預設定義的編碼風格"http://schemas.xmlsoap.org/soap/encoding/"。
<service name="stockquoteservice">
<documentation>股票查詢服務</documentation>
<port name="stockquoteport" binding="tns:stockquotebinding">
<soap:address location="http://example.com/stockquote"/>
</port>
</service>
</definitions>
這部分是具體的web服務的定義,在這個名為stockquoteservice的web服務中,提供了一個服務通路入口,通路位址是"http://example.com/stockquote",使用的消息模式是由前面的binding所定義的。