理解 SOAP

簡介

就在不久之前,SOAP 還不過是指肥皂而已。 而現在,大多數開發人員一聽到這個詞眼前就會浮現出一些尖括號來。 SOAP 最初表明「簡單對象訪問協議」。  若是在幾年前問任何一我的 SOAP 的含義,他們極可能這樣回答:「SOAP 是用來使 DCOM 和 Corba(例如,RPC 調用)在互聯網上工做」。  原做者們也認可,在那時他們注重於「訪問對象」,但隨着時間的推移,人們但願 SOAP 可以處理更普遍的狀況。 所以,SOAP 規範的重心很快從對象轉移到通用的  XML 消息處理框架上。html

這種重心的變化給 SOAP 縮寫詞中的 "O" 帶來了一點小問題。 有意思的是,SOAP 1.2 工做組沿用了(到目前爲止)SOAP  這個名稱(爲何不呢?這個詞太流行了),但決定再也不把這個詞拼出來以避免誤導開發人員。 現在,在最新的 SOAP 1.2 規範中,其正式的定義並不說起對象:web

SOAP 是一種輕量級協議,用於在分散型、分佈式環境中交換結構化信息。 SOAP 利用 XML  技術定義一種可擴展的消息處理框架,它提供了一種可經過多種底層協議進行交換的消息結構。  這種框架的設計思想是要獨立於任何一種特定的編程模型和其餘特定實現的語義。 編程

這個定義確實體現了 SOAP 如今的主旨。 SOAP 定義了一種方法以便將 XML 消息從 A 點傳送到 B 點(參見圖 1)。 爲此,它提供了一種基於 XML  且具備如下特性的消息處理框架:1) 可擴展,2) 可經過多種底層網絡協議使用,3) 獨立於編程模型。 如下將分別詳細討論這三種特性。數組

ms995800.understandsoap_01(zh-cn,MSDN.10).gif

圖 1. 簡單的 SOAP 消息處理  安全

首先,SOAP 可擴展性是關鍵所在。 在這個縮寫詞還表明某些含義時,"S" 意味着「簡單」。 若是咱們從 Web  中學到了同樣東西,那就是,簡單性老是比效率和純技術更重要,於是互操做性成敗的關鍵,就在於必須絕對要求簡單性。 簡單性仍然是 SOAP  的主要設計目標之一,這一點的例證就是 SOAP 缺乏分佈式系統的不少特性(如安全性、路由和可靠性等)。 SOAP  定義了一種通訊框架,容許以分層擴展的形式隨着時間推移而加入這些特性。 Microsoft、IBM 和其餘軟件廠商正在積極開發一個 SOAP  擴展的通用套件,該套件將加入大多數開發人員期待的特性。 這一計劃被稱爲全局 XML Web  服務結構 (GXA)Microsoft 已經發布了針對若干 GXA 規範的一個參考實現,並將其命名爲 Web  Services Enhancements 1.0 SP1 for Microsoft .NET (WSE)網絡

其次,SOAP 可在任何傳輸協議(諸如 TCP、HTTP、SMTP,甚至是 MSMQ)上使用(參見圖 1)。 然而,爲了保持互操做性,須要定義一些標準協議綁定以便草擬用於每種環境的規則。 SOAP 規範提供了一種用於定義任意協議綁定的靈活框架,而且因爲 HTTP  的使用極爲普遍,它現已爲 HTTP 提供了一種顯式綁定。數據結構

第三,SOAP 容許任何編程模型,而且不依賴於 RPC。 大多數開發人員馬上將 SOAP 與對分佈式對象進行的 RPC 調用等效起來(由於 SOAP  最初就是關於「訪問對象」的),但實際上,基本的 SOAP 模型更接近於傳統的消息處理系統,如 MSMQ。 SOAP 定義了一種模型以便處理個別的單向消息。  你能夠將多條消息組合成一條總體的消息交換。 圖 1 說明了一種簡單的單向消息,其中發送方不會收到響應。 可是,接收方能夠向發送方發回一條響應(參見圖 2)。  SOAP 容許使用任何數量的消息交換模式 (MEP),請求/響應只是其中一種。 其餘示例包括要求/響應(與請求/響應相對)、通知和長期運行的點對點對話等。架構

ms995800.understandsoap_02(zh-cn,MSDN.10).gif

圖 2. 請求/響應消息交換模式  app

開發人員常常將請求/響應與 RPC 混爲一談,而實際上兩者之間的差異很大。 RPC 使用請求/響應,但請求/響應不必定就是 RPC。 RPC 是  一種容許開發人員進行方法調用的編程模型。 RPC 須要將方法簽名轉換成 SOAP 消息。 鑑於 RPC 的普遍應用,SOAP 草擬了一項協議,以便將 RPC  用於 SOAP(參見本文稍後的RPC 和編碼一節)。框架

具有這三種主要特性,SOAP 消息處理框架就促進了在異構環境中交換 XML 消息,而在這類環境中,互操做性長久以來都是極大的挑戰。


 

SOAP 版本

從第一個發佈的 SOAP 規範到現在被普遍實施的 SOAP 1.1,不少方面都發生了改變,從瑣碎的細節到思想的重大轉變。 SOAP 1.1 被提交給 W3C,並於 2000 年 5 月被髮布爲 Note。因爲 SOAP 1.1  未能經過 W3C 過程的嚴格審覈,"W3C Note" 狀態使其還停留在僅是一個好主意的層次,但當完成時,它將最終達到「推薦」狀態。 然而,因爲現在 SOAP  1.1 獲得了大小廠商如此普遍的支持,它仍然被認爲是事實上的標準。

W3C 使用 SOAP 1.1 Note 做爲新 XML 協議工做組的基礎,負責產生下一版本的 SOAP,目前命名爲SOAP 1.2。 SOAP 1.2 當前是一種「候選推薦方案」,意味着它正處在實施階段且離最後完成爲期不遠。 一旦 SOAP 1.2  成爲「推薦方案」,它極有可能很快得到廠商的支持。

在 SOAP 1.2 發佈以後,爲了提供向後兼容性,廠商應該繼續支持 SOAP 1.1。 SOAP 版本控制基於 XML 命名空間。 SOAP 1.1 由  http://schemas.xmlsoap.org/soap/envelope/ 命名空間標識,而 SOAP 1.2 由  http://www.w3.org/2002/12/soap-envelope 命名空間標識(儘管當其成爲推薦方案時,這也將改變)。

有關每一個版本的命名空間名稱和規範所在位置,請參見表 1。 在本文的剩餘部分中,咱們將講述 SOAP 1.1 最重要的一些方面。 要了解兩個版本之間完整的更改列表,請查看當前的 SOAP 1.2 規範。

表 1. SOAP 版本信息

  • SOAP 1.1

  • 命名空間名稱

  • 規範位置

  • SOAP 1.2

  • 命名空間名稱

  • 規範位置


 

消息處理框架

SOAP 規範的核心部分就是消息處理框架。 SOAP 消息處理框架定義了一整套 XML 元素,用以「封裝」任意 XML 消息以便在系統之間傳輸。

該框架包括如下核心 XML 元素: Envelope、Header、Body 和 Fault,全部這些都來自 SOAP 1.1 中的  http://schemas.xmlsoap.org/soap/envelope/ 命名空間。 如下代碼中提供了 SOAP 1.1 的完整 XML  架構定義,以供在閱讀下文時參考。 我我的認爲,每次讓本身熟悉各類 XML 結構時,檢查一下該架構是很有幫助的。

SOAP 1.1 XML 架構定義

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"           xmlns:tns="http://schemas.xmlsoap.org/soap/envelope/"            targetNamespace="http://schemas.xmlsoap.org/soap/envelope/"  >         <!-- Envelope, header and body -->   <xs:element name="Envelope" type="tns:Envelope" />   <xs:complexType name="Envelope" >     <xs:sequence>       <xs:element ref="tns:Header" minOccurs="0" />       <xs:element ref="tns:Body" minOccurs="1" />       <xs:any namespace="##other" minOccurs="0"         maxOccurs="unbounded" processContents="lax" />     </xs:sequence>     <xs:anyAttribute namespace="##other"       processContents="lax" />   </xs:complexType>   <xs:element name="Header" type="tns:Header" />   <xs:complexType name="Header" >     <xs:sequence>       <xs:any namespace="##other" minOccurs="0"         maxOccurs="unbounded" processContents="lax" />     </xs:sequence>     <xs:anyAttribute namespace="##other"       processContents="lax" />   </xs:complexType>      <xs:element name="Body" type="tns:Body" />   <xs:complexType name="Body" >     <xs:sequence>       <xs:any namespace="##any" minOccurs="0"         maxOccurs="unbounded" processContents="lax" />     </xs:sequence>     <xs:anyAttribute namespace="##any"       processContents="lax" />   </xs:complexType>           <!-- Global Attributes -->   <xs:attribute name="mustUnderstand" default="0" >         <xs:simpleType>      <xs:restriction base='xs:boolean'>       <xs:pattern value='0|1' />     </xs:restriction>    </xs:simpleType>   </xs:attribute>   <xs:attribute name="actor" type="xs:anyURI" />   <xs:simpleType name="encodingStyle" >     <xs:list itemType="xs:anyURI" />   </xs:simpleType>   <xs:attribute name="encodingStyle"     type="tns:encodingStyle" />   <xs:attributeGroup name="encodingStyle" >     <xs:attribute ref="tns:encodingStyle" />   </xs:attributeGroup>   <xs:element name="Fault" type="tns:Fault" />   <xs:complexType name="Fault" final="extension" >     <xs:sequence>       <xs:element name="faultcode" type="xs:QName" />       <xs:element name="faultstring" type="xs:string" />       <xs:element name="faultactor" type="xs:anyURI"         minOccurs="0" />       <xs:element name="detail" type="tns:detail"         minOccurs="0" />           </xs:sequence>   </xs:complexType>   <xs:complexType name="detail">     <xs:sequence>       <xs:any namespace="##any" minOccurs="0"         maxOccurs="unbounded" processContents="lax" />     </xs:sequence>     <xs:anyAttribute namespace="##any"       processContents="lax" />    </xs:complexType> </xs:schema>

若是檢查一下 EnvelopecomplexType 定義,你很快就能瞭解這些元素相互之間是如何關聯的。 如下消息模板說明了  SOAP Envelope 的結構:

<soap:Envelope    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Header> <!-- optional -->     <!-- header blocks go here... -->   </soap:Header>   <soap:Body>     <!-- payload or Fault element goes here... -->    </soap:Body> </soap:Envelope>

Envelope 元素始終是 SOAP 消息的根元素。 這就便於應用程序識別「SOAP 消息」 — 只要檢查一下根元素的名稱便可。 經過檢查  Envelope 元素的命名空間,應用程序也可肯定所使用的 SOAP 版本。

Envelope 元素包含一個可選的 Header 元素(有關詳細信息,參見可擴展性一節),後跟一個必要的 Body 元素。 Body 元素表明了該消息的有效內容。 它是一種通用容器,由於它可包含來自任何命名空間的任意數量的元素。  這就是試圖發送數據的最終目的地。

例如,如下的 SOAP 消息表明了一個在銀行賬戶之間轉賬的請求:

<soap:Envelope  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">  <soap:Body>   <x:TransferFunds xmlns:x="urn:examples-org:banking">    <from>22-342439</from>    <to>98-283843</to>    <amount>100.00</amount>   </x:TransferFunds>  </soap:Body> </soap:Envelope>

若是接收方支持請求/響應,且可以成功地處理該消息,它應向最初的發送方返回另外一條 SOAP 消息。 在這種狀況下,響應信息也應包含在 Body  元素中,以下例所示:

<soap:Envelope  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">  <soap:Body>   <x:TransferFundsResponse    xmlns:x="urn:examples-org:banking">    <balances>     <account>      <id>22-342439</id>      <balance>33.45</balance>     </account>     <account>      <id>98-283843</id>      <balance>932.73</balance>     </account>    </balances>   </x:TransferFundsResponse>  </soap:Body> </soap:Envelope>

該消息處理框架還定義了一個名爲Fault  的元素,用於在發生錯誤時在 Body 元素中表示錯誤。  這是不可缺乏的,由於若是沒有一種標準的錯誤表示方法,每一個應用程序將不得不本身建立,從而使得通用基礎結構不可能區分紅功和失敗。 如下示例 SOAP  消息中包含了一個 Fault 元素,指明在處理該請求時發生了「Insufficient Funds(資金不足)」錯誤:

<soap:Envelope   xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">  <soap:Body>   <soap:Fault>    <faultcode>soap:Server</faultcode>    <faultstring>Insufficient funds</faultstring>    <detail>     <x:TransferError xmlns:x="urn:examples-org:banking">      <sourceAccount>22-342439</sourceAccount>      <transferAmount>100.00</transferAmount>      <currentBalance>89.23</currentBalance>     </x:TransferError>    </detail>   </x:TransferFunds>  </soap:Body> </soap:Envelope>

Fault 元素必須包含一個 faultcode,後跟一個 faultstring 元素。 faultcode  元素使用一種符合命名空間的名稱對錯誤進行分類,而 faultstring 元素提供一種對錯誤可讀的解釋(相似於 HTTP 的工做方式)。 表 2 簡要地說明了  SOAP 1.1 所定義的各類錯誤碼(全部這些代碼都包含在 http://schemas.xmlsoap.org/soap/envelope/  命名空間中)。

Fault 元素也可能包含一個 detail 元素,以便提供該錯誤的細節,這樣能夠幫助客戶端診斷問題,特別是在 Client 和 Server 錯誤碼的狀況下。

表 2. SOAP 1.1 錯誤碼

名稱

  • VersionMismatch

  • MustUnderstand

  • Client

  • Server

含義

  • 處理方發現 SOAP Envelope 元素的命名空間是無效的。

  • 處理方沒有理解或服從 SOAP Header 元素的某個直接子元素,而該子元素包含一個值爲 "1" 的 SOAP mustUnderstand   屬性。

  • Client 類的錯誤代表消息的格式錯誤或者不包含適當的信息,於是不能成功。 這一般代表,若是不對該消息作出更改,就不該該重發該消息。

  • Server 類的錯誤代表該消息未能獲得處理的緣由與消息的內容並無直接關係,而是跟該消息的處理有關。  例如,處理過程可能包括與某個上游處理器的通訊,但該處理器沒有響應。 若是在稍後重發,該消息可能會成功。

如今,假設你想在初始的消息中增長一些驗證信息,以便接收方可以肯定發送方是否有足夠的權限來執行傳輸。 要達到這一目的,一種方法就是在主體中添加憑證信息,以下所示:

<soap:Envelope  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">  <soap:Body>   <x:TransferFunds xmlns:x="urn:examples-org:banking">    <from>22-342439</from>    <to>98-283843</to>    <amount>100.00</amount>    <!-- security credentials -->    <credentials>     <username>dave</username>     <password>evad</password>    </credentials>   </x:TransferFunds>  </soap:Body> </soap:Envelope>

若是使用這種方法,每項須要驗證的操做都必須處理這些憑證。 這也意味着其餘須要安全性的應用程序必須開發本身的解決方案以解決這個問題;歸根結底,這將損害互操做性。  對於諸如安全性等公共須要,定義各方都贊成的標準 SOAP 標頭將更有意義。 而後,各廠商能夠在其通用的 SOAP 基礎結構中創建對擴展功能的支持,這樣各方皆贏。  這種方法可提升開發人員的生產力,同時有助於確保更高級別的互操做性。 而這正是 SOAP 擴展性模型設計要實現的目標。


 

擴展性

大多數現有的協議都區分控制信息(例如,標頭)和消息有效負載。 在這方面,SOAP 也不例外。 SOAP Header 和 Body 元素在易於處理的 XML  世界中也進行一樣的區分。 除了易用性以外,可擴展 Envelope 的關鍵優點在於它可用於任何通信協議。

在各類應用程序協議中(如 HTTP、SMTP 等)標頭老是具備重要的意義,由於標頭容許連網兩端的應用程序就所支持命令的具體行爲進行協商。 儘管 SOAP  規範自己並不定義任何內置的標頭,標頭將逐漸在 SOAP 中扮演同等重要的角色。 隨着 GXA 日趨成熟及 SOAP  標頭的標準化,開發人員可以更方便地定義豐富的應用程序協議,而沒必要每次都從新開始。

與 Body 元素相似,Header 元素是控制信息的通用容器。 其中可包含來自任何命名空間(除 SOAP 命名空間以外)的任意數量的元素。 放置在  Header 元素中的各個元素被稱爲標頭塊。  如同其餘協議同樣,標頭塊中包含的信息應該可以影響有效負載的處理。  所以,這裏正適於放置諸如憑證一類的元素,以幫助控制對操做的訪問:

<soap:Envelope  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">  <soap:Header>   <!-- security credentials -->   <s:credentials xmlns:s="urn:examples-org:security">    <username>dave</username>    <password>evad</password>   </s:credentials>  </soap:Header>  <soap:Body>   <x:TransferFunds xmlns:x="urn:examples-org:banking">    <from>22-342439</from>    <to>98-283843</to>    <amount>100.00</amount>   </x:TransferFunds>  </soap:Body> </soap:Envelope>

咱們也能夠利用一個名爲 mustUnderstand 的全局 SOAP 屬性對標頭塊進行標註,以指明接收方在處理該消息以前是否須要理解標頭。  如下示例說明了如何要求對憑證標頭進行處理:

<soap:Envelope  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">  <soap:Header>   <!-- security credentials -->   <s:credentials xmlns:s="urn:examples-org:security"    soap:mustUnderstand="1"   >    <username>dave</username>    <password>evad</password>   </s:credentials>  </soap:Header>  ...

若是某個標頭塊被標註爲 mustUnderstand="1",而接收方未設計爲支持給定的標頭,則不該處理該消息,而應該向發送方返回一條 Fault  (帶有 soap:MustUnderstand 狀態碼)。 若是 mustUnderstand="0" 或者沒有提供  mustUnderstand 屬性,則接收方能夠忽略相應的標頭塊並繼續進行處理。 在整個 SOAP 處理模塊中,mustUnderstand 屬性起着核心做用。


 

處理模型

SOAP 定義了一種處理模型,它大體規定了從 SOAP 發送方傳輸到 SOAP 接收方的過程當中對 SOAP 消息的處理規則。 圖 1說明了最簡單的 SOAP 消息處理方案,其中一個應用程序(SOAP 發送方)向另外一個應用程序(SOAP 接收方)發送一條 SOAP 消息。

可是,處理模型容許使用一些更有趣的結構(如圖 3 中的結構),這類結構中包含多個中間 節點。 在下文中,將使用 SOAP 節點  這個術語指代任何要處理 SOAP 消息的應用程序,無論是最初的發送方、中間節點仍是最終的接收方;不然,我將明確指出並使用相應的準確術語。

ms995800.understandsoap_03(zh-cn,MSDN.10).gif

圖 3. 高級 SOAP 消息處理  

中間節點位於最初的發送方和最終的接收方之間,並截獲 SOAP 消息。 中間節點可同時做爲 SOAP 發送方和 SOAP 接收方。  中間節點使得有可能設計一些有趣且靈活的網絡體系結構,而這些網絡結構能受到的消息內容影響。 SOAP 路由就是一個很好的示例,它很大程度上利用了 SOAP  中間節點(有關 SOAP 路由的詳細信息,請查看 Routing SOAP Messages  with Web Services Enhancements 1.0)。

在處理消息時,SOAP 節點承擔一個或者多個角色 (role),這些角色會影響如何處理 SOAP 標頭。 各個角色被賦予獨特的名稱(以 URI  的形式),以便在處理過程當中可以識別這些角色。 當 SOAP 節點接收到一條要處理的消息時,它首先必須肯定要假定哪些角色。 它能夠檢查該 SOAP  消息以幫助肯定。

一旦 SOAP 節點肯定了要扮演的角色,它隨後必須處理針對其角色之一的全部必要標頭(標記爲mustUnderstand="1" )。 SOAP  節點也可選擇處理針對其角色之一的任何可選標頭(標記爲 mustUnderstand="0")。

SOAP 1.1 只定義了一個名爲 http://schemas.xmlsoap.org/soap/actor/next 的角色(簡寫爲  next)。 每一個 SOAP 節點都必須承擔 next 角色。 所以,當 SOAP 消息到達任一給定的 SOAP  節點時,該節點必須處理針對 next  角色的全部必要標頭,它能夠選擇處理針對該 next 角色的可選標頭。 除 next  外,SOAP 1.2 定義了另一些角色(參見表 3),且應用程序也能夠定義自定義角色。

SOAP 標頭經過全局 actor 屬性(在 SOAP 1.2 中該屬性名爲 role )來指定具體的角色。 若是不存在 actor  屬性,則標頭默認地指向最終的接收方。 如下 SOAP 消息說明了如何使用 actor:

<soap:Envelope    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Header>     <wsrp:path xmlns:wsrp="http://schemas.xmlsoap.org/rp"     soap:actor="http://schemas.xmlsoap.org/soap/actor/next"     soap:mustUnderstand="1"     >     ...

因爲 wsrp:path 標頭被指定爲 next 角色且被標記爲必要的  (mustUnderstand="1"),所以接收到此消息的第一個 SOAP 節點必須根據該標頭塊的規範來處理此消息,在這種狀況下爲  WS-Routing。 若是 SOAP 節點不理解針對其角色之一的某個必要的標頭,則它必須產生一個帶 soap:MustUnderstand  狀態碼的 SOAP 錯誤,並中止處理。 SOAP Fault 元素提供了faultactor  子元素,以指定在消息路徑中哪一個節點致使了該錯誤的發生。faultactor  屬性的值是一個 URI,用以標識致使該錯誤的 SOAP 節點。

若是 SOAP 節點成功地處理了一個標頭,則它必須從消息中刪除該標頭。 SOAP 節點能夠再插入標頭,可是這樣作會改變合同方 —  它如今處於當前節點與該標頭所指向的下一節點之間。 若是 SOAP 節點剛好是最終的接收方,則它還必須處理 SOAP 主體。

表 3. SOAP 1.2 角色

SOAP 角色名稱

說明

  • 每一個 SOAP 中間節點和最終的 SOAP 接收方必須 (MUST) 扮演此角色,並能夠 (MAY) 另外承擔零個或多個其餘 SOAP 角色。

  • SOAP 節點毫不能夠 (MUST NOT) 扮演此角色。

  • 要將某個 SOAP 節點確立爲最終的接收方,該 SOAP 節點必須 (MUST) 扮演此角色。 SOAP 中間節點毫不能 (MUST NOT) 扮演此角色。


 

協議綁定

圖 3中一個有趣之處是 SOAP 容許經過多種底層協議進行消息交換。 因爲 SOAP 消息處理框架獨立於底層協議,每一箇中間節點能夠選擇使用不一樣的通訊協議而不會影響  SOAP 消息。 然而,爲了確保各類 SOAP 應用程序和基礎結構之間高級別的互操做性,標準的協議綁定是必要的。

一種具體的協議綁定準確地定義了應該如何利用給定的協議來傳輸 SOAP 消息。 換言之,它詳細定義了 SOAP  如何適用於另外一協議的範圍,該協議極可能具備本身的消息處理框架以及多種標頭。 協議綁定實際所定義的內容很大程度上取決於該協議的功能和選項。 例如,針對 TCP  的協議綁定應很大程度不一樣於針對 MSMQ 或針對 SMTP 的協議綁定。

SOAP 1.1 規範僅規範化了一種用於 HTTP 的協議綁定(因爲 HTTP 的普遍使用)。 SOAP 已經用於 HTTP  以外的不少協議,可是其實現並未遵循標準化的綁定。 當你嘗試與利用相同協議的其餘 SOAP  實施進行集成時,只要準備好處理各類互操做性方面的問題,超前一點而不使用標準的協議綁定也何嘗不可。


 

HTTP 綁定

HTTP 協議綁定定義了在 HTTP 上使用 SOAP 的規則。 SOAP 請求/響應天然地映射到 HTTP 請求/協議模型。 圖 4 說明了 SOAP  HTTP 綁定的不少細節。

ms995800.understandsoap_04(zh-cn,MSDN.10).gif

圖 4. SOAP HTTP 綁定  

HTTP 請求和響應消息的 Content-Type 標頭都必須設爲 text/xml (在 SOAP 1.2 中是  application/soap+xml)。 對於請求消息,它必須使用 POST 做爲動詞,而 URI 應該識別 SOAP 處理器。  SOAP 規範還定義了一個名爲 SOAPAction 的新 HTTP 標頭,全部 SOAP HTTP 請求(即便是空的)都必須包含該標頭。  SOAPAction 標頭旨在代表該消息的意圖。 對於 HTTP 響應,若是沒有發生任何錯誤,它應該使用 200 狀態碼,若是包含 SOAP  錯誤,則應使用 500


 

RPC 和編碼

儘管 SOAP 規範已日漸遠離對象,它仍然定義了一種約定,以便利用上述的消息處理框架來封裝並交換 RPC 調用。 定義一種標準的方法將 RPC 調用映射到  SOAP 消息,這使得在運行時基礎結構能夠在方法調用和 SOAP 消息之間自動轉換,而不用圍繞 Web 服務平臺從新設計代碼。

要利用 SOAP 進行方法調用,基礎結構須要如下信息:

  • 1.終結點位置 (URI)

  • 2.方法名稱

  • 3.參數名稱/值

  • 4.可選的方法簽名

  • 5.可選的標頭數據

這些信息能夠經過多種方法來傳輸,包括類型庫、IDL 文件,或者,更好的是 WSDL 文件。 SOAP RPC 綁定定義瞭如何在 SOAP  主體中封裝並表示這些信息。 爲此,RPC 綁定首先定義如何將方法簽名映射到簡單的請求/響應結構,而後將這些結構以 XML 進行編碼。 RPC  綁定規定將以一個按照方法命名的 struct 來模擬該方法調用。 該結構將包含對應於每一個 [in] 或  [in/out] 參數的一個訪問器,訪問器的名稱與參數名相同,其次序由消息簽名肯定。 方法響應也將做爲一個結構來建模。  結構的名稱可有可無,儘管約定是使用方法名後跟 "Response"(例如,對於 add 操做,方法響應名應該相應爲  addResponse)。 響應結構包含一個用於返回值的訪問器(其名稱在 SOAP 1.1 中可有可無,但在 SOAP 1.2 必須是  rpc:result),其後是針對每一個 [out][in/out] 參數的訪問器。

讓咱們來看一個示例。 假設 add 操做具備如下的 C# 方法簽名:

double add(ref double x, double y)

根據剛纔所說明的 RPC 綁定規則,表明該方法調用的請求結構應以下建模:

struct add {   double x;   double y; }

而響應結構以下:

struct addResponse {   double result;   double x; }

如今的問題是: 應該如何將這些結構映射到 XML(R) SOAP 規範定義了一組編碼規則,專門用於此用途。 SOAP  編碼規則大體闡述瞭如何將當今最經常使用的數據結構(如結構和數組)映射到普通的 XML 格式。 根據 SOAP 編碼規則,以上的請求結構應映射到如下 XML  消息(這將放在 SOAP 主體中):

<add>   <x>33</x>   <y>44</y> </add>

且上述請求的響應消息將映射到如下 XML 消息(這個消息將進入響應消息的主體):

<addResponse>   <result>77</result>   <x>33</x> </addResponse>

XML 架構的相關工做剛剛開始,SOAP 編碼規則即已創立。 既然 XML 架構已經完成,開發人員能夠簡單地提供文字的 XML 架構定義,從而準確指定應該如何以  XML 來格式化請求/響應消息。 因爲利用 XML 架構定義更易於得到互操做性,所以大多數開發人員已經決定徹底摒棄 SOAP 編碼規則。 實際上,自 SOAP  1.2 起,SOAP 規範再也不正式要求支持 SOAP 編碼規則。 從如今起,最好避免使用 SOAP 編碼規則,有關此中起因的全面討論,請查看關於 SOAP 編碼的討論一文。

儘管 SOAP RPC 綁定和編碼規則爲那些不肯意涉及諸如 XML 架構和 WSDL 等的應用程序提供了一個很好的 SOAP 集成層,由於 RPC  綁定和編碼規則易於致使互操做性方面的問題,它們基本上已經失寵於 Web 服務社區。


 

SOAP 類型

要重申的是,現在有兩種基本類型的 SOAP 消息處理: 文檔和 RPC。 文檔類型指出主體只是包含一個 XML 文檔,而發送方和接收方都必須遵循該文檔的格式。  另外一方面,RPC 類型指出主體中包含某個方法調用的 XML 表示,正如剛纔所述。

兩種方法可用於肯定如何將數據序列化到主體中: 使用文字的 XML 架構定義和使用 SOAP 編碼規則。 利用前一種方法,架構定義逐字肯定了主體的 XML  格式,不具備二義性。 然而,利用後一種方法,SOAP 處理器必須在運行時遍歷各類 SOAP 編碼規則以肯定主體正確的序列化。  很顯然,這種方法更易於致使錯誤和互操做性方面的問題。

最多見的情形是在使用文檔類型時也使用文字架構定義(稱爲文檔/文字),以及在使用 SOAP 編碼規則時使用 RPC 類型(稱爲  rpc/編碼)。 文檔/編碼和 rpc/文字也是可能的,但並不常見,也沒有太大意義。 大多數 Web  服務平臺都集中於文檔/文字類型,將其做爲發展的主要用例,且是現今 Microsoft ASP.NET WebMethod 框架的默認設置。


 

小結

SOAP 定義了一種簡單而可擴展的 XML 消息處理框架,它能夠經過多種協議用於各類不一樣的編程模型,儘管此規範中規範化瞭如何將 SOAP 用於 HTTP  和 RPC 調用。 SOAP 還定義了一個完整的處理模型,大體規定了當消息沿路徑傳送時如何對其進行處理。 總的來講,SOAP  提供了一個功能豐富而靈活的框架以便定義高級應用程序協議,這些協議可在分佈式異構環境中提供更好的互操做性。

相關文章
相關標籤/搜索