SOAP-Simple Object Access Protocol(簡單物件訪問協議)
原文連結 作者: Jakob Jenkov 譯者:趙亮
SOAP是Simple Object Access Protocol(簡單物件傳輸協議)的縮寫。SOAP訊息是基於XML格式進行傳輸的,流行的web service就是使用SOAP進行客戶端和伺服器之間的通訊的。在這篇文章中我將介紹基礎的SOAP格式(1.2版),包括:
- SOAP XML格式
- SOAP 訊息樣式
- SOAP MEP(Message Exchange Patterns 訊息交換模式 )
- SOAP 訊息路由選擇
- SOAP 通過HTTP傳輸
SOAP 訊息格式
下面是一個簡單的SOAP訊息:
<?xml version="1.0"?> <soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope" > <soap:Header> </soap:Header> <soap:Body> <-- Fault element is optional, used only if a fault occurs in web service. --> <soap:Fault> </soap:Fault> </soap:Body> </soap:Envelope>
正如你看到的,一條SOAP訊息包括一個envelope元素,在envelope元素中可以嵌套了一個Header元素和一個Body元素。如果在這個web service 處理訊息過程中產生了一個錯誤,在Body元素中可以巢狀一個Fault元素。在接下來的SOAP的文章中將會依次介紹SOAP訊息中的這些元素。
SOAP請求和響應都使用Envelope名稱空間
在早期的SOAP規範中從客戶端傳送請求到伺服器和從伺服器傳送響應到客戶端都使用相同的SOAP資料格式,因此SOAP請求和響應訊息格式是一致的。這不同於HTTP協議中請求和響應報文采用了不同的資料格式。
SOAP Envelope元素
SOAP的Envelope
下邊是一個關於SOAP Envelope元素的例子(內容中粗體內容為Envelope元素)
<?xml version="1.0"?> <env:Envelope xmlns:env="http://www.w3.org/2002/06/soap-envelope" > <env:Header> </env:Header> <env:Body> </env:Body> </env:Envelope>
注意到名稱空間env在Envelope元素中有如下定義
xmlns:env="http://www.w3.org/2002/06/soap-envelope"
名稱空間的定義必須總是出現在SOAP Envelope元素內,字首(env)可以視自己的喜好定義。
SOAP的Header元素
內容列表
- Header 子元素屬性
- mustUnderstand
- encodingStyle
- role
- relay
SOAP Header元素是Envelope元素的一個可選的子元素,在Header元素內你可以放置SOAP資訊中Body部分一外的內容,其中的內容可以完全由你來指定,例如,它可以是關於這條SOAP請求處理的最大時間,或者是其它沒有在SOAP訊息中直接被指明的內容。
下邊是一個關於SOAP Header元素的例子(內容中粗體內容為Header元素)
<?xml version="1.0"?>
<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope" >
<env:Header>
<jj:maxTime value="10000" xmlns:jj="http://jenkov.com"/>
</env:Header>
<env:Body>
</env:Body>
</env:Envelope>
上邊的例子展示了僅有一個“SOAP 頭資訊塊”的Header元素。
更多的關於Header元素的使用類似於Envelope元素的XML名稱空間的內容請參考SOAP規範。
Header子元素屬性
Header元素的子元素有以下幾個標準屬性:
- mustUndersstand
- encodingStyle
- role
- relay
接下來的部分將詳細介紹這幾個元素屬性。
mustUnderstand
mustUnderstand屬性意味著每個處理SOAP的節點必須能夠理解(處理)所給出的Header區域。這裡所說的“節點”不一定是最終接收SOAP訊息的節點,這條SOAP訊息在到達最終接收/處理訊息的節點(web service)之前可能經過了中間某些節點。
假如中間的一個節點不能理解含有mustUnderstand屬性的header區域中的內容,那麼必須返回SOAP錯誤資訊。
錯誤資訊例子如下:
<env:Header>
<jj:maxTime value="10000" xmlns:jj="http://jenkov.com"
mustUnderstand="true"
/>
</env:Header>
encodingStyle
encodingStyle屬性內容省略。
role
某個節點在處理/轉發SOAP訊息過程中都扮演者一個或多個SOAP角色,Header區域(元素)能夠將資訊傳送給訊息路徑中的特定的角色,換句話說,如果Header區域中指定了”ultimateReceiver”角色,那麼訊息路徑中“ultimateReceiver”角色必須處理Header區域,訊息路徑中的其它節點將不對Header區域中的內容進行處理。
SOAP角色詳細解釋見“SOAP 角色”
下邊是一個使用role屬性的例子:
<env:Header>
<jj:maxTime value="10000" xmlns:jj="http://jenkov.com"
role="http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver"
/>
</env:Header>
在這個例子中header元素<maxTime …>僅指定為該SOAP訊息的最終接收者處理,訊息路徑的中間節點將忽略header元素中的內容。
relay
relay屬性決定了如果header區域沒有被處理是否可以被轉發,換句話說,如果訊息路徑中的中間節點沒有處理Header元素中的內容,在轉發SOAP訊息的過程中需要根據relay屬性來判斷header元素是否可以被轉發?
relay屬性只有兩個合法的值:
- true
- false
如果relay屬性設定為’true’那麼沒有處理的Header元素可以被轉發。
如果relay屬性設定為’false’那麼沒有處理的Header元素不可以被轉發。
預設relay條件情況下等同於relay屬性設定為’false’。
下邊是一個使用relay屬性的例子:
<env:Header>
<jj:maxRelayTime value="10000" xmlns:jj="http://jenkov.com"
role="http://www.w3.org/2003/05/soap-envelope/role/next"
relay="true"
/>
</env:Header>
在這個例子中Header元素<maxRelayTime …>必須在節點間進行轉發,就算已經被處理過了,換句話說,SOAP訊息在訊息路徑中轉發過程中Header元素不應該被省去。正如你所看到的role屬性被設定為”next”,這意味著所有訊息路徑中的節點都需要處理Header元素。
SOAP Body元素
SOAP Body元素是客戶端和web serveice伺服器端處理的SOAP訊息中的最主要的部分,SOAP訊息中Header元素是可選的但是Body元素是必須要有的元素,SOAP訊息中必須包含Body元素。
下邊是一個關於SOAP Header元素的例子(內容中粗體內容為Header元素)
<?xml version="1.0"?>
<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope" >
<env:Header>
<jj:maxTime value="10000" xmlns:jj="http://jenkov.com"/>
</env:**Header**>
<env:Body>
</env:Body>
</env:Envelope>
上邊的例子展示了僅有一個“SOAP 頭資訊塊”的Header元素。
更多的關於Header元素的使用類似於Envelope元素的XML名稱空間的內容請參考SOAP規範。
Header元素的子元素的屬性
Header元素的子元素有以下幾個標準屬性:
- mustUndersstand
- encodingStyle
- role
- relay
每一個元素將會在接下來進行詳細的介紹。
mustUnderstand
mustUnderstand屬性意味著每個處理SOAP的節點必須能夠理解(處理)所給出的Header區域。這裡所說的“節點”不一定是最終接收SOAP訊息的節點,這條SOAP訊息在到達最終接收/處理訊息的節點(web service)之前可能已經經過了訊息路徑中的某些節點。
假如中間的一個節點不能理解含有mustUnderstand屬性的header區域中的內容,那麼必須返回SOAP錯誤資訊。
錯誤資訊例子如下:
<env:Header>
<jj:maxTime value="10000" xmlns:jj="http://jenkov.com"
mustUnderstand="true"
/>
</env:Header>
encodingStyle
encodingStyle屬性內容省略
role
某個節點在處理/轉發SOAP訊息過程中都扮演者一個或多個SOAP角色,Header區域(元素)能夠將資訊傳送給訊息路徑中的特定的角色,換句話說,如果Header區域中指定了”ultimateReceiver”角色,Name只有訊息路徑中“ultimateReceiver”角色必須處理Header區域,訊息路徑中的其它節點將不對Header區域中的內容進行處理。
SOAP角色詳細解釋見“SOAP 角色”
下邊是一個使用role屬性的例子:
<env:Header>
<jj:maxTime value="10000" xmlns:jj="http://jenkov.com"
role="http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver"
/>
</env:Header>
在這個例子中header元素<maxTime …>僅指定為該SOAP訊息的最終接收者處理,訊息路徑的中間節點將忽略header元素中的內容。
relay
relay屬性決定了如果header區域沒有被處理是否可以被轉發,換句話說,如果訊息路徑中的中間節點沒有處理Header元素中的內容在轉發SOAP訊息的過程中需要根據relay屬性來判斷header元素是可以被轉發?
relay屬性只有兩個合法的值:
- true
- false
如果relay屬性設定為’true’那麼沒有處理的Header元素可以被轉發。
如果relay屬性設定為’false’那麼沒有處理的Header元素不可以被轉發。
預設relay條件情況下等同於relay屬性設定為’false’。
下邊是一個使用relay屬性的例子:
<env:Header>
<jj:maxRelayTime value="10000" xmlns:jj="http://jenkov.com"
role="http://www.w3.org/2003/05/soap-envelope/role/next"
relay="true"
/>
</env:Header>
在這個例子中Header元素<maxRelayTime …>必須在節點間進行轉發,就算已經被處理過了,換句話說,Header元素不應該被省去。正如你所看到的role屬性被設定為”next”,這意味著所有訊息路徑中的節點都需要處理Header元素。
SOAP Body元素
SOAP Body元素是客戶端和web serveice伺服器端處理的SOAP訊息中的最主要的部分,Header元素是可選的但是Body元素是強制的,SOAP訊息中必須包含Body元素。
下邊是一個關於SOAP Body元素的例子(內容中粗體內容為Body元素)
<?xml version="1.0"?>
<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope" >
<env:Header>
</env:Header>
<env:Body>
</env:Body>
</env:Envelope>
SOAP訊息的Body部分可以包含幾乎所有的你想放置的格式正確的XML資料,然而你不能在Body元素內直接放置文字內容,文字內容應該放置在Body元素的子元素內。
推薦Body元素的子元素使用符合規範的名稱空間。
這裡有兩個關於Body元素的例子。第一個例子中Body元素中包含了4個元素,第二個例子這4個元素巢狀在了<service>元素內。
<?xml version="1.0"?>
<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope" >
<env:Body>
<jj:operation name="setName"
xmlns:jj="http://jenkov.com/operation" />
<jj:param name="userId" value="123456"
xmlns:jj="http://jenkov.com/params" />
<jj:param name="firstName" value="Jakob"
xmlns:jj="http://jenkov.com/params" />
<jj:param name="lastName" value="Jenkov"
xmlns:jj="http://jenkov.com/params" />
</env:Body>
</env:Envelope>
<?xml version="1.0"?>
<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope" >
<env:Body>
<jj:service name="userService"
xmlns:jj="http://jenkov.com/service" >
<jj:operation name="setName" />
<jj:param name="userId" value="123456" />
<jj:param name="firstName" value="Jakob" />
<jj:param name="lastName" value="Jenkov" />
</jj:service name="userService"
</env:Body>
</env:Envelope>
SOAP Fault元素
內容列表
- SOAP Fault元素結構
- code
- Reason
- Node
- Role
- Detail
如果訊息路徑中的節點在處理SOAP訊息的過程中產生了錯誤,Fault元素出現在從web service(或中間節點)返回的SOAP訊息中的Body元素中。
下邊是一個關於SOAP Fault元素的例子(內容中粗體內容為Fault元素)
<?xml version="1.0"?>
<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope" >
<env:Body>
<env:Fault>
<env:Code>
<env:Value>env:Sender</env:Value>
</env:Code>
<env:Reason>
<env:Text xml:lang="en-US">Processing error</env:Text>
<env:Text xml:lang="da">Processerings-fejl</env:Text>
</env:Reason>
</env:Fault>
</env:Body>
</env:Envelope>
SOAP Fault元素結構
SOAP Fault元素有如下的結構:
<env:Fault>
<env:Code>
<env:Value>env:Sender</env:Value>
<env:Subcode>
<env:Value>env:Sender</env:Value>
<env:Subcode> <-- recursive Subcode's possible -->
</env:Subcode>
</env:Subcode>
</env:Code>
<env:Reason>
<env:Text xml:lang="en-US">Error in Input Data</env:Text>
<env:Text xml:lang="da">Fejl i input data</env:Text>
</env:Reason>
<env:Node>http://jenkov.com/theNodeThatFailed</env:Node>
<env:Role>
http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver
</env:Role>
<env:Detail
<jj:maxRelayTime
xmlns:jj="http://jenkov.com" >10000</jj:MaxRelayTime>
</env:Detail>
</env:Fault>
Code元素和Reasong元素是必須要有的,Node、Role和Detail元素是可選的
Code
Code元素是必須要有的,在Code元素內可以巢狀Value元素,如果你需要分解錯誤碼還可以新增可選的SubCode子元素。
Value子元素只能包含以下列表中的值,這些值必須新增名稱空間資訊,這就意味著如果你在SOAP訊息中添加了Envelope元素的名稱空間資訊對映字首為”env”,你也需要為下邊列表中的值新增字首”env”,例如:”env:Sender”。
Value Describe
VersionMismath 訊息路徑中的節點發現在SOAP訊息中的根節點不是有效是Envelope元素將會報告這個錯誤MustUnderstand 訊息路徑中的節點不能理解Header元素的某一個含有mustUnderstand屬性的子元素,這樣的一個目標節點將會報
告這個錯誤,換句話說訊息路徑中的此節點不能理解此Header元素假設他能理解的元素的意思。DataEncodingUnknow 訊息路徑中的節點不能理解假定被理解的元素的編碼(由encodingStyle屬性被指定)
Sender SOAP訊息格式錯誤、不包含有效的資料或者缺少資料等,換句話說,訊息的傳送方傳送了錯誤的SOAP訊息。
Receiver SOAP訊息的接收者不能處理此訊息。責任完全在訊息的接收方,例如:web service需要資料庫支援但是資料庫
宕機了。
你可以自己定義Subcode元素包含任何值到Value子元素中,Subcode元素可以迴圈巢狀Subcode元素
下面是Code元素的例子
<env:Code>
<env:Value>env:Sender</env:Value>
<env:Subcode>
<env:Value>env:Sender</env:Value>
<env:Subcode> <-- recursive Subcode's possible -->
</env:Subcode>
</env:Subcode>
</env:Code>
Reason
Reason元素是強制要有的,Reason元素可以包含一個或者多個Text元素作為子元素,Text元素包含任何語言格式的錯誤的原因,Text元素的lang屬性可以是ISO規定的語言程式碼值。
下面是包含相同錯誤資訊的英語和丹麥語的例子
<env:Reason xmlns:xml="http://www.w3.org/XML/1998/namespace" >
<env:Text >Error in Input Data</env:Text>
<env:Text xml:lang="da">Fejl i input data</env:Text>
</env:Reason>
Node
Node元素是可選的,他應該包含當前發生錯誤的URI識別符號,URI識別符號可以自定義。
下面是例子:
<env:Node>http://jenkov.com/theNodeThatFailed</env:Node>
Role
Role元素是可選的,他應該包含訊息路徑中產生錯誤的節點的角色,“角色”詳細資訊見“SOAP 角色”相關內容。
下面是例子
<env:Role>
http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver
</env:Role>
Detail
Detail元素是可選的,他應該包含描述錯誤產生詳細資訊的子元素,不能直接將文字資訊放置在Detail元素內,所有的文字資訊需要放置在Detail元素的子元素內。
所有的Detail元素的子元素應該使用合法的名稱空間,表明這些子元素屬於自己的名稱空間。
下面是例子:
<env:Detail
<jj:maxRelayTime
xmlns:jj="http://jenkov.com" >10000</jj:MaxRelayTime>
</env:Detail>
SOAP Roles元素
內容
- 預定義SOAP Roles
- 使用者SOAP Roles
- Header元素中的SOAP Roles
- Fault元素中的SOAP Roles
訊息路徑中處理/轉發SOAP訊息的節點被認為是扮演著一個或多個SOAP角色,這裡有一個示意圖展示了包含3個節點的SOAP訊息處理過程:
處理過程中節點角色.
第一個節點是訊息的傳送者,這個節點的角色在SOAP規範中沒有被提及。
第二個節點是進行SOAP訊息轉發的中間節點,中間的節點也可以改變SOAP訊息的內容,例如:它們可以新增、修改或者是刪除Header元素或者改變Body元素中的內容,中間節點被定義為扮演者”next”角色。
圖中SOAP訊息中的最後一個節點是”ultimateReceiver”,最終的接收節點是最終的SOAP訊息的處理者,是”web service”的另一個說法,可以理解為”web service”實際上包含了整個處理SOAP訊息的所有節點不僅僅是最終的接收者。
預定義的SOAP角色
SOAP規範預定義的三個角色:
所有的中間節點和最終接收節點被假定為next角色
none角色比較特殊,不包含任何節點,到達該角色的SOAP訊息Header區域在該節點的左側沒有被處理過或者是在處理其它Header區域時已經被使用過。
ultimateReceiver角色為SOAP訊息的最總接收者保留,沒有該角色屬性的Header區域不能處理此區域。
使用者自定義SOAP Roles
SOAP角色並不僅限於上一節中預定義的三種角色,SOAP角色可以是任何自定義的角色,如果你定義了你自己的角色,你也必須同時定義角色的語義,換句話說你必須決定這些自定義角色所執行操作的意義。
Header元素中SOAP角色
SOAP Header元素可以使用SOAP角色
下面是Header元素使用role屬性:
<env:Header>
<jj:maxTime value="10000" xmlns:jj="http://jenkov.com"
role="http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver"
/>
</env:Header>
當Header元素的子元素包含role屬性,只有作為這個角色的節點才可以處理此元素,所有其它節點都不做處理。
Fault元素中的SOAP角色
SOAP 角色也可以用在Fault元素,Fault元素中的角色資訊用來說明產生錯誤的節點的角色。
下面是Fault元素巢狀Role元素的例子:
<env:Fault>
<env:Code>
<env:Value>env:Sender</env:Value>
</env:Code>
<env:Reason>
<env:Text xml:lang="en-US">Error in Input Data</env:Text>
</env:Reason>
<env:Node>http://jenkov.com/theNodeThatFailed</env:Node>
<env:Role>
http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver
</env:Role>
</env:Fault>
SOAP訊息交換模式
內容
- 請求-響應模式
- 響應模式
SOAP規範提到了一個概念”message exchange patterns” (MEP) 。在SOAP規範中有兩種訊息交換模式:
- 請求-響應
- 響應
本小節將對這兩種訊息交換模式進行描述。
請求-響應模式
請求-響應訊息交換模式是SOAP客戶端傳送一個SOAP請求訊息到伺服器端,伺服器端以SOAP格式的訊息返回客戶端。
當SOAP服務需要SOAP客戶端傳送的資料才能執行任務時,請求-響應訊息交換模式是必要的,例如:如果客戶端需要將資料儲存在伺服器端,那麼客戶端必須把需要被儲存的資料傳送到伺服器端。
下邊圖例描述了請求-響應訊息交換:
SOAP請求-響應訊息交換
響應模式
響應訊息交換模式是SOAP客戶端連線到伺服器端,但是不向伺服器傳送SOAP訊息內容,而是傳送一個簡單的HTTP請求,然後伺服器返回響應的SOAP訊息。
這種訊息交換模式和瀏覽器與web伺服器進行通訊的方式相似,瀏覽器傳送一個HTTP請求去請求相應的頁面,但是這個HTTP請求沒有攜帶任何額外的資料,然後web伺服器返回請求的頁面。
響應訊息交換模式的圖例:
SOAP響應訊息交換