SOAP技術與B2B應用集成(2)
SOAP的消息結構與數據的組織方法
本文最初由 IBM developerWorks 中國網站發表,其網址是
http://www.ibm.com/developerWorks/cn/
SOAP爲在一個鬆散的、分佈的環境中使用XML對等地交換結構化的和類型化的信息提供了一個簡單的輕量級機制。而傳送信息的基本單元承載體就是SOAP消息。從根本上來看,SOAP消息是從發送方到接受方的一種傳輸方法,但就象前面SOAP技術及應用概覽一文中闡述的那樣,SOAP消息一般會和實現模式結合,例如請求/響應。SOAP的實現可以爲特殊網絡系統的特有特徵來優化。例如,通過HTTP binding將SOAP響應消息通過HTTP響應來傳輸,請求和響應使用同一連接。
當然,無論SOAP是與哪種協議綁定,它都使用同一種消息的描述框架格式,這種框架格式就是以SOAP Envelope(SOAP信封)爲根元素,內含SOAP Header和SOAP Body子元素的這樣一個XML文檔。SOAP消息描述文本是一種XML Application。之所以稱之爲描述框架,而不稱爲描述,是因爲SOAP規範爲SOAP Header和SOAP Body定義了強大的擴展機制,使用戶可以按需要在其中增加與應用相關的自定義描述格式,SOAP規範只是定義了消息描述的一個骨架。
所有的SOAP消息都是使用XML格式來編碼的。SOAP應用程序在生成由SOAP定義的所有元素和屬性的時候,應該包含恰當的SOAP的命名空間。SOAP應用程序必須能處理其收到的消息中的SOAP命名空間。它必須丟棄那些包含不正確命名空間的消息,並且可以處理那些不包含SOAP命名空間的SOAP消息,就好象他們包含了正確的命名空間一樣。
SOAP定義了兩個命名空間:
SOAP信封的命名空間標識爲http://schemas.xmlsoap.org/soap/envelope/
SOAP編序的命名空間標識爲http://schemas.xmlsoap.org/soap/encoding/
SOAP消息必須不包含DTD,同時SOAP消息也必須不包含PI(Processing Instructions)。
除SOAP mustUnderstand attribute和SOAP actor attribute外,一般允許屬性及屬性值自由地選擇是在XML實例中描述還是在XML Schema中描述,當然前提是他們具有相同的效果。也就是說,在模式(schema)中使用默認值或固定值定義在語義上等價於在實例中的值定義。
例如:在Schema中定義
<element name=”company” type=”string” fixed=”DealEasy”>
然後在XML實例中定義
<company />
與直接在XML實例中定義
<company>DealEasy</company>
在語義上是等價的。
SOAP的消息框架
SOAP消息是由一個強制的SOAP Envelope、一個可選的SOAP Header和一個強制的SOAP Body組成的XML文檔。作爲SOAP消息的該XML文檔將在本規範的其餘部分被引用。而本節的元素和屬性的命名空間標識是http://schemas.xmlsoap.org/soap/envelope/。SOAP消息應當包含如下部分:
§ Envelope是表示該消息的XML文檔的頂級元素
§ Header則是爲了支持在鬆散環境下在通訊方之間尚未預先達成一致的情況下爲SOAP消息增加特性的通用機制。SOAP定義了很少的一些屬性來用於指明誰可以處理該特性以及它是可選處理的還是強制處理的。
§ Body爲該消息的最終接收者所想要得到的那些必須處理的信息提供了一個容器。此外,SOAP定義了Body的一個子元素Fault用於報告錯誤。
這些XML元素的語法規則如下:
1. Envelope
§ 元素名爲 Envelope
§ 該元素必須在SOAP消息中出現,一般是根元素
§ 該元素可以包含命名空間申明和額外的屬性。如果出現額外屬性(並非是SOAP規範預定義的屬性),則必須使用命名空間修飾。類似的,該元素可以包含額外的子元素,這些子元素如果出現,必須有命名空間修飾並且必須跟在SOAP Body元素之後,也就是說Envelope的直接子元素Header和Body必須排列在最前面。
2. Header
§ 元素名爲 Header
§ 該元素可以在SOAP消息中出現,但並不是必須出現(也就是說可以僅使用Body元素完成一次SOAP消息的信息描述)。如果出現,該元素必須是SOAP Envelope元素的第一個直接子元素。
§ 該元素可以包含一系列的Header條目,這些條目都應當是Header元素的直接子元素。Header的所有直接子元素必須有命名空間修飾。
§ Header條目自身可以包含下級子元素,但這些元素不是Header條目,而是Header條目的內容。
3. Body
§ 元素名爲 Body
§ 該元素必須在SOAP消息中出現,同時必須是SOAP Envelope元素的一個直接子元素。若該消息中包含Header元素,則Body元素必須直接跟隨Header,爲Header元素的相鄰兄弟元素。若Header不出現,則其必須是Envelope的第一個直接子元素。
§ 該元素可以包含一系列的Body條目,這些條目都應當是Body元素的直接子元素。Body的所有直接子元素必須有命名空間修飾。SOAP定義了SOAP Fault元素,它用來指示調用錯誤的信息。
§ Boidy條目自身可以包含下級子元素,但這些元素不是Body條目,而是Body條目的內容。
下面是一個SOAP消息的例子,其中Envelope包含一個Header元素和一個Body元素。Header元素有兩個Header條目,他們的命名空間修飾都是uniB2B,兩個Header條目各有一個子元素。而Body元素有一個Body條目,該條目包含兩個子元素。
<SOAP-ENV:Envelope
xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Header>
<uniB2B:AccessAuthenticated xmlns:uniB2B=”Some-URI”>
<SessionKey>76E4#12A@-98JA#V5GQ</SessionKey>
</uniB2B:AccessAuthenticated >
<uniB2B:GetLastProductPrice xmlns:uniB2B ="Some-URI">
<Price>243900.00</Price>
</uniB2B:GetLastProductPrice>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<uniB2B:RequestPurchaseOrder xmlns:uniB2B ="Some-URI">
<ProductID>Jaguar_X_Type</ProductID >
<ProductPrice>243900.00</ProductPrice>
</uniB2B:RequestPurchaseOrder >
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
SOAP encodingStyle屬性
SOAP的全局encodingStyle屬性被用於指明在SOAP消息中使用哪種編序規則。該屬性可以在任意元素中出現,並且其作用範圍包括該元素的內容和所有其子元素中未使用該屬性的所有子元素,這就象XML命名空間定義的作用範圍一樣,是向下傳遞的。對於一個SOAP消息來說,沒有默認的編碼定義。
SOAP encodingStyle屬性的值是一個或多個用於標識編序規則(對數據類型和數據類型實例的描述規則)和用於標識解序SOAP消息的規則的有序列表,其排序是按照詳盡程度從大到小排列。下面是一些值的例子:
"http://schemas.xmlsoap.org/soap/encoding/"
"http://schema.dealeasy.com/soap/encoding/ http://schema.dealeasy.com/soap/encoding/additional/"
""
而SOAP規範中定義的編序規則的標識爲http://schemas.xmlsoap.org/soap/encoding/。消息若要使用特別的編序應該使用SOAP encodingStyle屬性來指明。另外,所有在句法上由http://schemas.xmlsoap.org/soap/encoding/開始的URI序列表明這其中包含的所有URI都與SOAP規範中定義的SOAP編碼規則相一致。(雖然可能會添加潛在的更爲嚴格的規則,也就是說http://schemas.xmlsoap.org/soap/encoding/標識的編碼規則是一個編碼的基類)
一個空值的URI(“”)明確地指明並未爲其所包含的元素聲明任何編碼風格。這可以爲包含的元素關閉任何前面預先的聲明。
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
SOAP Header
SOAP提供了一個可擴展的機制用於在分散的網絡環境下,模塊化地擴展SOAP消息的描述能力,而通訊雙方並不需要有完整的預先的約定。典型的擴展例子可以是實現一些諸如認證、事務管理以及支付的Header條目,當然對於更復雜的多步驟的B2B協同,通過擴展相對複雜的Header條目也可以實現,在前面的文章SOAP技術及應用概覽中就有一個完整的例子。
按照SOAP的語法,Header元素應當被編碼爲SOAP Envelope XML文檔的第一直接子元素。Header的所有直接子元素都被稱爲Header條目。
Header條目的編碼規則包括:
1. 一個Header條目由一個完整修飾的元素名來標識,所謂完整修飾的元素名是由一個命名空間URI和局部名來組成。SOAP Header元素的所有直接子元素都必須是完整修飾的。不允許任何不帶命名空間修飾的Header條目存在。
2. SOAP encodingStyle屬性可以用於指明Header條目的編碼風格,而encodingStyle屬性在前面已經詳細介紹了。
3. SOAP mustUnderstand屬性和SOAP actor屬性可以用於指明如何處理條目和由誰來處理條目。
在SOAP Header中,SOAP Header屬性的設置是爲了讓SOAP消息的接收者瞭解應該如何處理該消息。一個生成SOAP消息的SOAP應用程序應該僅使用SOAP Header元素的直接子元素的SOAP Header屬性。而對於那些並非作爲SOAP Header元素的直接子元素出現的SOAP Header屬性,SOAP消息的接受者必須忽略。
以下是一個Header的例子,其中包含了一個元素標識Priority和一個mustUnderstand屬性及其值1,以及Priority的值7,該元素表明該消息的處理優先權爲7。
<SOAP-ENV:Header>
<uniB2B:Priority
xmlns:uniB2B="some-URI" SOAP-ENV:mustUnderstand="1">
7
</uniB2B:Priority>
</SOAP-ENV:Header>
SOAP actor屬性
SOAP消息從生成者到達最終接受者,將潛在地沿着消息路徑(message path)經過一系列的SOAP中間介。SOAP中間介是一個能夠接受和轉發SOAP消息的應用程序。所有的中間介都如同最終接受者一樣由一個URI來標識。
並非一個SOAP消息的所有部分都是最終接收者需要了解的調用信息,其中部分是路徑中的一個或多箇中間介所需要處理的。Header元素中接收者角色類似合約的接受者,他並不能將其交給其它方。也就是說,一個接收者接到其需要接收的Header元素必須不轉發該Header給SOAP消息路徑中的下一個應用程序。該接收者可以插入一個類似的Header元素,但在這個情況下,合約關係存在於該應用程序及下一個Header元素的接收者之間了。
SOAP actor全局屬性可以被用於指明Header元素的接收者。而SOAP actor屬性的值是一個URI。URI: http://schemas.xmlsoap.org/soap/actor/next指明該Header元素是直接的下一個進行消息處理的SOAP應用程序需要處理的。這與HTTP的連接頭字段的hop-by-hop scope model的表示是一致的。
若省略SOAP actor屬性,則表明該消息的接收者是SOAP消息的最終接收者。
對於一個SOAP消息的實例(在實際傳輸中的SOAP消息),這個屬性必須出現以指明該消息的接收方的URI。
SOAP mustUnderstand屬性
SOAP mustUnderstand全局屬性用於指明一個Header條目是強制必須處理的還是可選的要求接收者處理的。Header條目的接收者由SOAP actor屬性來定義。mustUnderstand屬性的值可取爲“0”或“1”。若沒有使用SOAP mustUnderstand屬性,則在語義上等價於mustUderstand屬性出現同時取值爲“0”。
若Header元素帶有值爲“1”的SOAP mustUnderstand屬性,則該Header條目的接收者要麼必須遵循語義(由具備完整修飾的元素名來傳達)並正確地處理這些語義,要麼必須宣稱處理消息失敗。也就是說如果該應用程序發現自己無法識別某一個Header條目(應爲在自己的處理邏輯裏面沒有該條目),那麼必須申明錯誤,並響應該錯誤信息。
SOAP mustUnderstand屬性是爲了考慮健壯地升級而設置的。所有用值爲“1”的SOAP mustUnderstand屬性來標記的元素必須被認爲是可以影響該元素的上級元素或同級元素的語義。而這種風格標記的元素應保證對語義的修改並不能被那些不能完全理解該修改後的語義的那些元素靜默地或假設地、不正確地忽略。
該屬性若要生效必須在實例中出現,也就是說不能依靠XML Schema的缺省值或固定值的設置來使該屬性生效。。
SOAP Body
SOAP Body元素提供一個簡單的用於與消息的最終接收者交換信息(這些信息都是必須處理的)的機制。而Body元素的典型應用包含序列的RPC調用和錯誤報告。
Body元素在編碼上應當作爲SOAP Envelope元素的一個直接子元素。如果包含Header元素,則Body元素必須直接跟隨Header元素,爲Header元素的直接下一個兄弟元素,否則Body元素必須是Envelope元素的第一直接子元素。
所有Body元素的直接子元素被稱爲Body條目,同時每一個Body條目都應當編碼爲SOAP Body元素裏的一個獨立元素。
Body條目的編碼規則包括:
1. 一個Body條目由一個完整修飾的元素名來標識,所謂完整修飾的元素名是由一個命名空間URI和局部名來組成。SOAP Body元素的直接子元素可以是命名空間修飾的。
2. SOAP encodingStyle屬性可以被用來表明Body條目中使用的編碼規則。
SOAP只預定義了一個Body條目:用於向調用方報告錯誤的Body條目:Fault。
SOAP Body的應用
下面是一對SOAP調用/響應的例子,在調用消息中Body包含了一個描述調用方法的Body條目RequestPurchaseOrder,它包含兩個參數ProductID和ProductPrice。而在響應消息中,Body中包含了一個Body條目ResponsePurchaseOrder用於描述響應調用的返回信息,其中包含OrderID、AuthenticatedID、ProductID、ProductNumber、IssueDate。
RPC調用的SOAP消息表示
POST /ProductQuote HTTP/1.1
Host: service.eMarketplace.com.cn
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: "Some-URI"
<SOAP-ENV:Envelope
xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Header>
<uniB2B:AccessAuthenticated xmlns:uniB2B=”Some-URI”>
<SessionKey>76E4#12A@-98JA#V5GQ</SessionKey>
</uniB2B:AccessAuthenticated >
<uniB2B:GetLastProductPrice xmlns:uniB2B ="Some-URI">
<Price>243900.00</Price>
</uniB2B:GetLastProductPrice>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<uniB2B:RequestPurchaseOrder xmlns:uniB2B ="Some-URI">
<ProductID>Jaguar_X_Type</ProductID >
<ProductPrice>243900.00</ProductPrice>
</uniB2B:RequestPurchaseOrder >
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
RPC響應的SOAP消息表示
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
<SOAP-ENV:Envelope
xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<uniB2B:ResponsePurchaseOrder xmlns:uniB2B ="Some-URI">
<OrderID>AJR786503</OrderID>
<AuthenticatedID>76E4#12A@-98JA#V5GQ</AuthenticatedID>
<ProductID>Jaguar_X_Type</ProductID >
<ProductPrice>243900.00</ProductPrice>
<ProductNumber>1</ProductNumber>
<IssueDate>2001-4-1</IssueDate>
</uniB2B:ResponsePurchaseOrder >
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
SOAP Header和SOAP Body的語義關係
Header和Body在定義上是獨立的,但在事實上是相聯繫的。一個Body條目和一個Header條目的關係是:一個Body條目在語義上與這樣一個Header條目等價:該Header條目將由默認參與者(最終接受者)解釋同時由值爲“1”的SOAP mustUnderstand屬性標記。默認參與者可以不使用actor屬性的方式來指明。
SOAP Fault
SOAP Fault元素是用於在SOAP消息中傳輸錯誤及狀態信息。如果SOAP消息需要包含SOAP Fault元素的話,它必須作爲一個Body條目出現,同時在Body元素內它必須不出現多於一次(至多出現一次)。
SOAP Fault元素定義瞭如下子元素:
faultcode
faultcode元素是應那些要以算法的機制來標識錯誤的軟件的需要。faultcode必須在SOAP Fault元素中出現,同時faultcode的值必須是屬於後面一節中定義的一個修飾名。SOAP定義了一個很小的SOAP錯誤代碼的集合用於覆蓋基本的SOAP錯誤。
faultstring
faultstring元素是爲那些錯誤代碼提供人可以讀懂的錯誤解釋,它不是爲程序處理而設。Faultstring元素有點類似於HTTP中定義的’Reason-Phrase’。faultstring必須在SOAP Fault元素中出現,同時它至少應該提供一些解釋該錯誤種類的信息。
faultactor
faultactor元素是爲在消息路徑中是誰引起了該錯誤的發生這一情況描述信息。它類似於SOAP actor屬性,不過它不是用於指示Header條目的接收者,而是用於指示錯誤源。faultactor屬性的值是一個標識該源的一個URI。作爲SOAP消息的非最終接收者的應用程序必須在SOAP Fault元素中包含faultactor元素。而消息的最終接收者可以使用faultactor元素來明確地指明是它生成了該錯誤。
detail
detail元素是用於傳輸與Body元素相關的應用程序特別的錯誤信息。如果Body元素中的內容不能被成功地處理的時候,它必須出現。它必須不能被用於傳輸屬於Header條目的錯誤信息。詳細的屬於Header條目的錯誤信息必須在Header條目中表示傳輸。
若Fault元素中不出現detail元素則表明其中的錯誤與Body元素的處理無關。這可以用於區分在在錯誤情況下Body元素是否被處理過。
detail元素的所有直接子元素都被稱爲detail條目,同時每個detail條目都作爲detail元素中的一個獨立的元素進行編碼。
Detail條目的編碼規則如下:
1. 一個detail條目由一個完整修飾的元素名來標識,所謂完整修飾的元素名是由一個命名空間URI和局部名來組成。Detail元素的直接子元素可以是命名空間修飾的。
2. SOAP encodingStyle屬性可以被用來表明detail條目中使用的編碼規則。
其他的Fault子元素可以出現,他們都應當提供命名空間修飾。
SOAP Fault Codes
當描述由本規範定義的錯誤的時候,faultcode元素必須使用在本節中定義的faultode的值。這些faultcode值的命名空間標識爲http://schemas.xmlsoap.org/soap/envelope/。
默認的SOAP faultcode值是按照一種可擴展的風格來定義的,它允許在維持以有的faultcode值的向後兼容的基礎定義新的SOAP faultcode值。這一機制在使用上非常類似與HTTP中基本狀態類的定義1xx, 2xx, 3xx等。不過,他們是用XML修飾名來定義,而不是用整數。“.”符號是faultcode值的分隔符,用於指明“.”左邊的是一個比右邊更泛化的錯誤代碼。例如:
Client.Authentication
在本文檔中定義的faultcode值集合是:
Name Meaning
VersionMismatch 處理程序發現在SOAP Envelope元素中有一個非法的命名空間。
MustUnderstand SOAP Header元素的一個直接子元素無法被理解或者他並不遵守由處理對象要求的SOAP mustUnderstand屬性必須取值爲“1”的要求。
Client Client錯誤類用於指示以下錯誤:消息的格式有誤或消息中缺乏能成功處理所必須的一些適當信息。例如,消息中可能缺乏適當的認證和支付信息。一般情況下應指明消息不應該在沒有修改過的情況下重發。可參閱Fault detail子元素的描述。
Server Server錯誤類用於表明消息無法被處理的原因,但那些屬於內容上的錯誤並不屬於該範疇,它主要被用於指示那些屬於處理上的錯誤。例如,處理操作需要包含與一個上游處理程序進行通訊,但該程序沒有響應。但該消息可能在下一個時間點上被成功處理。可參閱Fault detail子元素的描述。