原帖地址:http://www.ibm.com/developerworks/cn/webservices/ws-address.html

Doug Davis, 架構師, IBM

2004 年 4 月 01 日

Web 服務尋址(WS-Addressing)協(xié)議可能與第一眼看上去的的樣子有很大的不同。但是它構建的消息信息頭將使新的 Web 服務消息流模式成為可能——而且它將對 SOAP 引擎以及 SOAP 協(xié)議本身的未來造成深遠的影響。

大約在一年以前,IBM、BEA 和 Microsoft 推出了一個稱為 Web 服務尋址(WS-Addressing)的新規(guī)范(請參閱下面參考資料部 分的相關鏈接)。在整個 14 頁里,它僅僅聲明了幫助人們如何標準化指定 Web 服務的位置的方法。然而,Web 服務尋址(WS-Addressing)具有從根本上改變 SOAP 處理模型的潛力。但是,究竟是怎樣改變的呢?而且,更重要的是,為什么要改變呢?為了更好地回答這些問題,讓我們先來研究一下這個規(guī)范本身究竟說了些什 么。(應該注意的是,這里的討論將并不探討這個規(guī)范的實際實現(xiàn)的細節(jié);相反,我將討論為什么它在 SOAP 中的角色將來會那么關鍵。)

如果您正確地了解了事實,那么在所有多余的話之后,Web 服務尋址(WS-Addressing)實際上只包括兩個新概念:端點引用(endpoint reference,EPR)和 SOAP 結構的消息信息(message information,MI)頭。

端點引用(Endpoint reference)

在 Web 服務尋址(WS-Addressing)出現(xiàn)以前,為了找到一個 Web 服務的位置,您不得不請求端點的 URL 或求助于 Web 服務描述語言(WSDL)。這聽起來好像夠簡單了,那么您為什么還需要 Web 服務尋址(WS-Addressing)呢?隨著 Web 服務的發(fā)展,很自然,它們將開始變得復雜,以便支持企業(yè)級的解決方案。例如,可能需要在 SOAP 請求中包含附加信息來幫助惟一地識別您正在與之對話的 Web 服務實例。這將與在請求中包含會話標識符或實例 ID 相類似。這么做并不是非常的重要。

然而,使用會話標識符(通過將某些像 resourceID=123 這樣的信息附加到 URL)并不完全類似于 SOAP。SOAP 純粹主義者可能更愿意回到 SOAP 中定義的可擴展性模型,并使用附加的 SOAP 頭包含這個新的信息來處理消息;例如:

<widget:resourceID>123</widget:resourceID>

從技術上來說,兩種方法中的任何一種 ——改變請求的 URL 或在 SOAP 頭中包含識別信息——都可以很好地滿足這些目的。然而,如果您使用 SOAP 頭而不是在 URL 中編碼這個附加信息,那么您將不再綁定于一個特定的傳輸協(xié)議。想象這樣一種情況,一個 SOAP 消息為了到達它的最終目的地實際上通過了多個傳輸協(xié)議。如果兩個傳輸協(xié)議都是 HTTP,那么就可以很容易地重用 URL 的查詢字符串部分。但是其他的傳輸協(xié)議怎么辦呢,比如 SMTP?resourceID=123 是去哪?它可能變成 SMTP 頭嗎?如果傳輸不支持用戶定義的字段怎么辦?或者,即使它支持,SOAP 消息的最終接收方(SOAP 引擎)將如何知道怎樣向 Web 服務傳送這些用戶定義的字段呢?

URL 編碼的另外一個問題是,現(xiàn)在它將特定于 Web 服務的數(shù)據(jù)緊密地綁定到傳輸——換句話說,現(xiàn)在特定于 Web 服務的數(shù)據(jù)在 SOAP 信封以外,處于傳輸層。

那么,Web 服務尋址(WS-Addressing)有什么用處呢?它定義了稱為端點引用(endpoint reference,EPR)的東西。在它最簡單的形式中,EPR 只不過就是由一些 XML 元素包裝的 URL。清單 1 給出了一個示例。

清單 1. 一個簡單的端點引用(EPR)
  <widget:myLocation>
<wsa:Address>http://localhost/WidgetService</wsa:Address>
</widget:myLocation>

這里,widget:myLocation 是端點引用(EPR),在它的內部是一個 Web 服務尋址的(WS-Addressing-defined)定義的元素,稱為 wsa:Address (當試圖與 WidgetService 對話時,使用它來指定 URL)。

清單 2 添加了附加資源 ID 信息。

清單 2. 帶有添加的 ReferenceProperties 元素的端點引用(EPR)
  <widget:myLocation>
<wsa:Address>http://localhost/WidgetService</wsa:Address>
<wsa:ReferenceProperties>
<widget:resourceID>123</widget:resourceID>
</wsa:ReferenceProperties>
</widget:myLocation>

這夠容易了:您可以添加一個稱為 ReferenceProperties 的新 XML 元素,并且在它的內部有一個包含特定于您的 Web 服務的數(shù)據(jù)的元素,稱為 resourceID (也稱為引用特性(reference property))。這個 ReferenceProperties 元素可以封裝所有特定于 Web 服務的數(shù)據(jù)。但是現(xiàn)在您將如何處理這個 XML 塊呢?因為您正在使用 resourceID,那就繼續(xù)使用它,并且假定您之所以使用這個附加信息是因為存在由 WidgetService 使用的多個 Widget 實例。您可以設想,在某種程度上,您或者創(chuàng)建了一個實例,或者請求服務返回一個指向實例的指針。假定您請求了通過調用某個 createWidget() 操作來創(chuàng)建的一個新的實例。但是,WidgetService 是怎樣返回到這個新的 widget 的引用的呢?正如您可能已經(jīng)猜到的,它是通過返回一個端點引用(EPR)來實現(xiàn)的,如清單 3 所示。

清單 3. 使用端點引用(EPR)來返回引用
  <soap:Envelope...>
<soap:Body>
<widget:createWidgetResponse...>
<widget:widgetReference>
<wsa:Address>http://host/WidgetService</wsa:Address>
<wsa:ReferenceProperty>
<widget:resourceID>123</widget:resourceID>
</wsa:ReferenceProperty>
</widget:widgetReference>
</widget:createWidgetResponse>
</soap:Body>
</soap:Envelope>

在這里,widgetReference 是一個端點引用(EPR)。Web 服務尋址(WS-Addressing)規(guī)范要求 Address 元素,但是 resourceID 是特定于 WidgetService 的。

您 可能一邊看這個例子,一邊納悶,為什么您不是僅僅返回字符串“123“,而是返回整個端點引用(EPR)——為什么您需要增加額外的復雜性?實際上,有幾 個原因說明了為什么額外的抽象實際上最后會使工作更容易。首先,消息的接收方不需要知道端點引用(EPR)的任何內容。如果您返回像“123”這么簡單的 信息,那么接收方將不得不既要知道這是一個字符串,而且還要知道這個字符串的含義以及稍后應該如何使用這個字符串。潛在地,接收方可能被要求有區(qū)別地解釋 返回值,這取決于它正在對話的應用程序的類型。通過使用端點引用(EPR),您已經(jīng)使 Web 服務的引用的格式標準化,更確切地說,也使 Web 服務的實例的引用的格式標準化了。

端點引用(EPR)的另外一個重要方面是必需的元素:Address。因為端點引用(EPR)具有這個 Address 字段,所以這個字段可以包含與原始請求的 URL 完全不同的 URL。例如,createWidget() 調用的 URL 可能以 .../createWidgetService 結束,而隨后服務調用的 URL 可能是 .../WidgetService。不必理會特定的值,關鍵是這個端點引用(EPR)的接收方不需要知道任何關于如何解釋數(shù)據(jù)的事情;它僅僅需要知道 Address 字段是應該用于未來消息的 URL,以及所有的引用特性(reference properties)應該都是在那些消息中的 SOAP 頭。所以,對于這個端點引用(EPR)的未來請求的 SOAP 信封將采用清單 4 中所給出的形式。

清單 4. 用于請求我們的樣本端點引用(EPR)的 SOAP 信封
  <soap:Envelope...>
<soap:Header>
<wsa:To> http://host/WidgetService </wsa:To>
<widget:resourceID>123</widget:resourceID>
</soap:Header>
<soap:Body>
...
</soap:Body>
</soap:Envelope>

這個信封將被發(fā)送到 http://host/WidgetService(我很快將討論 wsa:To 頭)。現(xiàn)在,WidgetService 順利處理這個 SOAP 消息所需的全部信息都可以在信封中獲得,沒有什么是特定于傳輸協(xié)議的——而且最重要的是,客戶端應用程序完全不知道這個附加信息(消息的接收方需要它(比 如,引用特性)來順利地處理消息)。一般來說,所有的客戶端基礎設施都需要知道如何處理端點引用(EPR)。

所 以,現(xiàn)在您已經(jīng)將傳送 Web 服務的引用的方法標準化了。標準化是一件好事,但是到目前為止,您幾乎還沒有看到前面聲稱的 Web 服務尋址(WS-Addressing)將改變 SOAP 本身所具有的優(yōu)點。在下一部分中,您會對此有更好的理解,接下來我們介紹 Web 服務尋址(WS-Addressing)的第二個特征:消息信息(message information,MI)頭。





回頁首


消息信息頭(MI header)

Web 服務尋址(WS-Addressing)規(guī)范定義了一些附加的(當然,也是標準的)SOAP 頭,它們應該用于幫助傳送關于消息的信息。在這一部分中,我將介紹其中比較有趣的一些。

To

To 只不過是目標 Web 服務的 URL。一般來說,這個 URL 和 HTTP 請求的 URL 是相同的,但是這并不是必需的。

清單 5. To 頭
      	<wsa:To> http://host/WidgetService </wsa:To>

當使用端點引用(EPR)時,To 頭應該與 <wsa:Address> 元素具有相同的值——查閱前面的部分中的例子可以獲得更多的細節(jié)。

From

From 是消息發(fā)送方的端點引用(EPR)。如果消息接收方需要向發(fā)送消息的端點發(fā)送回消息,那么它應該使用這個端點引用(EPR)。請注意,同樣也有一個 ReplyTo 頭,它指示響應消息應該去往何處。From 頭將用于這樣的情況,如同那些由 WS-ReliableMessage 規(guī)范所管理的,Acknowledgement 需要被發(fā)送回發(fā)送方。清單 6 給出了一個運行的 From 頭示例。

清單 6. From 頭
      <wsa:From> 
<wsa:Address> http://client/myClient </wsa:Address>
</wsa:From>

ReplyTo

正如所提到的,來自于 Web 服務的任何響應都應該被發(fā)送給 ReplyTo 端點引用(EPR)。因為 FromReplyTo 可能是兩個截然不同的端點引用(EPR),所以消息的發(fā)送方可能并不是想要接收響應的端點。我將在稍后討論這里的含義。清單 7 舉例說明了 ReplyTo 頭的使用。

清單 7. ReplyTo 頭
      <wsa:ReplyTo>
<wsa:Address> http://client/myReceiver </wsa:Address>
</wsa:ReplyTo>

FaultTo

如果消息的響應是 SOAP 錯誤,那么這個錯誤應該在 FaultTo 頭中發(fā)送給端點引用(EPR)。清單 8 給出了一個示例。

清單 8. FaultTo 頭
      <wsa:FaultTo>
<wsa:Address> http://client/FaultCatcher </wsa:Address>
</wsa:FaultTo>

MessageID

MessageID 只不過就是惟一地識別消息的 URI。清單 9 給出了一個示例。

清單 9. MessageID 頭
	      <wsa:MessageID>uuid:098765</wsa:MessageID>

Action

清單 10 中顯示的 Action 頭是 SOAP HTTP Action 頭在信封中的版本。

清單 10. Action 頭
      <wsa:Action> http://host/widgetOp </wsa:Action>

RelatesTo

RelatesTo 常常用在響應消息中,用來指示它與先前知道的消息相關并且定義這種關系。Listing 11 給出了一個示例。

清單 11. RelatesTo 頭
<wsa:RelatesTo RelationshipType="wsa:Response">
uuid:098765
</wsa:RelatesTo>

清單 11 中的 RelatesTo 頭指示,這是先前知道的請求(Request)消息(它的 MessageIDuuid:098765)的響應(Response)消息。在異步消息傳遞場景中,這個信息頭是很關鍵的——響應消息的接收方必須能夠將它與原始請求消息相關聯(lián)。RelatesTo 頭提供了標準機制來達到這個目的。





回頁首


使用信息頭

Web 服務尋址(WS-Addressing)定義了所有這些要使用的特殊的頭,但是您可能會這樣自問:“誰關心這些?”最初,您事實上已經(jīng)添加了一定程度的復 雜性,似乎直到現(xiàn)在都還沒有用上。對于簡單的請求/響應 HTTP 消息流,可能是這樣的。然而,一旦您開始使用異步消息流或跨多個傳輸協(xié)議發(fā)送消息時,這些頭就變得非常重要了。

以一個簡單的異步消息交換(甚至是在 HTTP 之上)為例,在這里響應消息通過一個新的連接發(fā)送回去。服務器是如何知道下一個響應消息需要去往何處呢?一個顯而易見的解決方案就是將返回地址(或者端點引用)作為應用程序數(shù)據(jù)的一部分(即,包含在 Body 中)。然而,如果您使用 Web 服務尋址(WS-Addressing),那么現(xiàn)在您就有一個標準位置用于這個數(shù)據(jù):ReplyTo 消息信息頭/端點引用(MI header/EPR)。同樣地,如果您使用的是類似于 Web 服務可靠消息傳遞(WS-ReliableMessaging)(參閱參考資料)這樣的規(guī)范,那么在這里潛在地有三個不同的響應消息(傳統(tǒng)的 Reply、可能有的 Fault 以及 Acknowledgement),Web 服務尋址(WS-Addressing)提供了一個標準機制,所有的 Web 服務通過這個機制就可以表示這個信息。當這三個消息可能需要發(fā)送給三個不同的端點時,這就變得尤為關鍵。這與實際信封所采用的方式毫無差別,在實際信封上 有用于書寫收信人地址、寄信人地址和粘貼郵票的標準位置。標準化是一件好事。





回頁首


匿名 URI

在所有的信息頭(或者包含 Address 元素,或者像 To 頭那樣對自己進行尋址)中,您可以使用一個特殊的匿名 URI:

http://schemas.xmlsoap.org/ws/2003/03/addressing/role/anonymous

當您使用這個 URI 時,您就暗示,對于這個地址并沒有可用的真正端點。這就意味著不能打開到那個端點的連接。實際上,這對消息流有一些非常有趣的副作用。例如,讓我們假設您在 ReplyTo 頭的地址中使用了匿名 URI。這是什么意思呢?明顯地,客戶端不想打開一個新的連接——它不是一個真正的 URI。使用匿名 URI 就相當于根本不使用 ReplyTo 頭——換句話說,響應必須在 HTTP 響應消息中流回。

雖然最初您可能覺得這個例子只是比較有趣地使用 ReplyTo 和匿名 URI,而實際上,它對于消息處理模型具有非常大的影響。考慮這樣一種情況,它的請求消息類似于清單 12 所示。

清單 12. 使用匿名 URI
  <soap:Envelope...>
<soap:Header>
<wsa:To> http://host/WidgetService </wsa:To>
<wsa:ReplyTo>
<wsa:Address>
http://schemas.xmlsoap.org/ws/2003/03/addressing/role/anonymous
</wsa:Address>
</wsa:ReplyTo>
<wsa:FaultTo>
<wsa:Address>
http://client/myReceiver
</wsa:Address>
</wsa:FaultTo>
...
</soap:Header>
<soap:Body>
...
</soap:Body>
</soap:Envelope>

注意,這個消息的發(fā)送方要求通過 HTTP 響應流發(fā)送回響應消息(正如在 ReplyTo 頭中匿名 URI 所指示的)。這意味著發(fā)送這個代碼的客戶端假定同步處理模型,是這樣嗎?有可能。看一下 FaultTo 頭——那是一個真正的、非匿名的端點。所以,如果這個消息的接收方產(chǎn)生一個 SOAP 錯誤,那么應該將那個錯誤發(fā)送到 http://client/myReceiver, 而且不通過 HTTP 響應流——那是一個異步處理模型。考慮它真正的意思是什么:在某些情況中,客戶端不能控制消息的傳回是同步地,還是異步地。這可能會對 SOAP 引擎造成非常大的影響。它們不再能夠假定每次調用一個處理模型——它們必須能夠基于從服務器取回的信息來在兩者之間轉換。所以,在這種情況下,客戶端可能 等待 HTTP 響應流上的響應。如果沒有得到,那么它將等待異步到達 http://client/myReceiver 端點上的響應。這個動態(tài)的轉換可能對于當前某些 SOAP 處理器來說并不是一個簡單的任務。

當然,并不只是客戶端受到了影響。接收方(或服務器)必須能夠基于各種信息頭中的值和生成的響應消息來動態(tài)地在同步模型和異步模型之間轉換。

它還有另外一個有趣的副作用。在大部分服務中,WSDL 描述的是非常簡單的請求/響應同步消息模式。但是對于 Web 服務尋址(WS-Addressing)來說,任何 Web 服務(無論是異步地還是同步地)都將簡單地通過正確地使用 Web 服務尋址(WS-Addressing)頭來隱式地支持異步。這是 SOAP 應用程序現(xiàn)在可用的一個非常強大的工具。某些規(guī)范,比如 WS-Transactions (WS-Coordination 和 WS-AtomicTransaction——請查閱參考資料),特意定義了兩個不同的端口類型——一個用于同步消息傳遞模式,一個用于異步消息傳遞模式。這種差別現(xiàn)在已經(jīng)變得過時了。

新興技術工具包(Emerging Technologies Toolkit,ETTK;請參閱 參考資料以 獲得相關鏈接)包括使用 Web 服務尋址(WS-Addressing)規(guī)范的相當多的演示。特別是,基于 Web 的 WS-ReliableMessaging demo 讓您可以容易地改變 Web 服務尋址(WS-Addressing)頭來查看消息流是如何改變的。





回頁首


結束語

支 持 WS-* 規(guī)范最一般的原因是由于它帶給 Web 服務世界的標準化程度。Web 服務尋址(WS-Addressing)通過定義端點引用(EPR)和消息信息(MI)頭來明確地達到這個目的。這個定義提供了單一的機制,通過這一機 制,人們能夠指定 Web 服務(或者服務的實例)的位置以及服務在 SOAP 消息中使用那些端點引用(EPR)的方式(通過 MI 頭)。但是,正是在消息處理模型/流中的隱式改變甚至對 SOAP 具有更加重大的影響。Web 服務尋址(WS-Addressing)的重要性將隨著時間而增加——以致到達它將被視為那些規(guī)范中的一個成員,它本身應該是核心 SOAP 規(guī)范的一部分。



參考資料



關于作者


Doug Davis 是 IBM Software Standards 部門的架構師。他以前擔任過的職務包括 Emerging Technologies Toolkit、WebSphere Machine Translation、Team Connection 和 IBM Fortran 90 的技術總監(jiān)。