- 服務互聯(lián)網運行原理與實踐
- 王菁等
- 3字
- 2024-01-25 18:36:58
2.1 服務
2.1.1 SOAP服務
Web服務及其協(xié)議棧是對SOA理念最初的一種嘗試。它將服務實現(xiàn)為一種可以自包含、自描述及模塊化的Web組件,并通過Web進行發(fā)布、查找和調用。WSDL、SOAP和UDDI是對Web服務來說最重要的三個協(xié)議。WSDL定義了如何描述一個Web服務;SOAP定義了怎樣調用并觸發(fā)一個Web服務;UDDI則定義了如何發(fā)布、管理及查找Web服務的描述信息。為了和后面介紹的REST服務區(qū)分,本書將使用SOAP的Web服務統(tǒng)稱為SOAP服務。
W3C(萬維網聯(lián)盟)對SOAP服務的定義如下。
定義2.1 SOAP服務(SOAP service):一種支持機器間通過網絡交互的軟件系統(tǒng)。它的接口描述是機器可處理的(通常采用WSDL語言)。服務之間的交互采用SOAP消息,并通過Web相關標準及基于HTTP協(xié)議的XML消息交換方式實現(xiàn)交互(Haas et al. 2004)。
作為一個新興的分布式計算平臺,SOAP服務除了達成互操作方面的承諾,在可靠通信、安全、事務、管理、編程模型和協(xié)作協(xié)議等方面都有相應的規(guī)范和協(xié)議。
2.1.1.1 SOAP
SOAP(simple object access protocol)是“簡單對象訪問協(xié)議”的簡稱,它的初始目的是提供一種基于XML文本的通信協(xié)議,以實現(xiàn)DCOM和CORBA之間的互操作。但是,隨著Web服務理念和技術的逐漸成熟,SOAP規(guī)范的重心很快從對象轉移到通用的XML消息處理框架上。這種重心的變化給SOAP這一縮寫詞的定義帶來了一點小問題。SOAP 1.2工作組沿用了SOAP這個名稱,但決定不再使用該詞的起始全稱以免誤導開發(fā)人員,因此在最新的SOAP 1.2規(guī)范中,其正式的定義并不提及“object”一詞。
SOAP是一個輕型的分布式計算協(xié)議,它允許在一個分布式的環(huán)境中交換信息。SOAP沒有與硬件平臺、操作系統(tǒng)、編程語言或網絡硬件平臺捆綁。與其他分布式計算系統(tǒng)不同的是,SOAP建立在開放式標準的頂部,如HTTP和XML。SOAP用基于文本的XML協(xié)議與分布式系統(tǒng)通信,而非用其他分布式計算協(xié)議(如CORBA、RMI和DCOM)使用的二進制格式。這使得SOAP具有跨硬件平臺、操作系統(tǒng)、編程語言和網絡硬件平臺的高度互操作性。SOAP可以在HTTP上傳輸,HTTP允許它利用已有的基礎設施投資,如Web服務器、代理服務器和防火墻。SOAP也可以用其他協(xié)議(如SMTP和JMS)進行傳輸。
SOAP規(guī)范的主要目標是簡單性和可擴展性。
(1)簡單性:SOAP規(guī)范定義的消息結構非常簡單,除了這個基本消息結構,SOAP沒有定義額外的表述結構標準,沒有定義自己的編碼格式,也沒有定義自己的傳輸協(xié)議;而且,SOAP還避免了許多與組件模型有關的復雜功能,如分布式垃圾收集、對象引用、對象激活及消息批處理等。
(2)可擴展性:SOAP使用XML來封裝遠程調用和交換的數(shù)據(jù),SOAP非常具有彈性,因為它可以使用XML來封裝所有的數(shù)據(jù),并且擴充它的功能和意義,同時能夠通過標準的XML分析技術來進行消息解析。
2.1.1.2 SOAP消息處理模型
最簡單的SOAP消息處理模型如圖2-1所示:XML格式的SOAP消息通過某種網絡通信協(xié)議(如HTTP、SMTP等)在SOAP消息發(fā)送方和接收方之間傳送。

圖2-1 最簡單的SOAP消息處理模型
高級SOAP消息處理模型如圖2-2所示:SOAP消息從起始發(fā)送方發(fā)出后,經過多個中間節(jié)點到達最終接收方。

圖2-2 高級SOAP消息處理模型
SOAP消息中間節(jié)點(簡稱SOAP節(jié)點)位于起始發(fā)送方和最終接收方之間,截獲SOAP消息并進行相應的處理。大體來說,SOAP消息由消息頭和消息體構成,中間節(jié)點只能對SOAP消息頭進行處理和修改,而無權處理和修改SOAP消息體,這點在SOAP1.2規(guī)范中有明確定義。
在處理消息時,SOAP節(jié)點將會承擔一個或多個角色,SOAP節(jié)點的角色決定節(jié)點如何處理SOAP消息頭。當SOAP節(jié)點接收到一條消息時,它首先必須確定其自身的角色,其次看自己是否必須處理該消息(由消息頭中的mustUnderstand屬性決定)。
2.1.1.3 SOAP消息結構
SOAP消息結構的基本模型如圖2-3所示:整個SOAP消息包含在一個信封中,信封內有一個SOAP消息頭和一個SOAP消息體,其中SOAP消息頭是可選的,消息頭和消息體可以包含多個條目,SOAP消息體可以包含SOAP故障。

圖2-3 SOAP消息結構基本模型
上述SOAP消息的概念模型如圖2-4所示。
對SOAP消息概念的解釋如下。
(1)信封(Envelope):信封是SOAP消息的根元素,包含一個可選的SOAP消息頭元素和一個必需的SOAP消息體元素。
(2)消息頭(Header):消息頭是可選元素,其中可以包含多個任意格式的項,比如描述安全性、事務處理、會話狀態(tài)信息的項。

圖2-4 SOAP消息概念模型
(3)消息體(Body):消息體是必需元素,代表實際的消息負載,可以包含多個任意格式的項,這些項可以采用兩種XML結構風格,即文檔風格或RPC風格,本節(jié)后續(xù)會詳細討論這兩種風格。
(4)故障(Fault):故障是可選元素,用于攜帶出錯信息。故障只能作為消息體元素的直接子元素,并且一個消息體元素只能包含一個故障元素。
下面詳細介紹SOAP消息的各組成部分。
1.SOAP信封
SOAP信封是SOAP消息的根元素,SOAP信封包含兩個子元素:一個是可選的消息頭,另一個是必需的消息體。在SOAP信封元素中,可以通過XML命名空間定義SOAP消息的版本信息,也可以通過XML命名空間定義編碼風格。
1)soapEnv:SOAP消息版本
soapEnv命名空間標明了SOAP消息的版本,其中:
SOAP1.1命名空間的URI是:http://schemas.xmlsoap.org/soap/envelope/;
SOAP1.2命名空間的URI是:http://www.w3.org/2003/05/soap-envelope/。
按照SOAP規(guī)范,一個SOAP信封必須與上述命名空間中的一個相關聯(lián),不遵守上述命名空間聲明的SOAP消息會被視為一個版本錯誤。
2)encodingStyle:編碼風格
SOAP消息通常需要定義的另一個命名空間是SOAP消息的編碼風格encodingStyle(關于編碼風格詳見2.1.1.4節(jié))。
SOAP1.1編碼風格的URI是:http://schemas.xmlsoap.org/soap/encoding/;
SOAP1.2編碼風格的URI是:http://www.w3.org/2003/05/soap-encoding/。
2.SOAP消息頭
SOAP消息頭是可選的。如果SOAP信封中包含消息頭元素,那么它必須作為根元素信封的第一個子元素出現(xiàn)。SOAP消息頭也是可擴展的,用戶可以自行添加一些用于描述安全性和事務處理的數(shù)據(jù),Web服務規(guī)范WS-Security、WS-Transaction等都是SOAP消息頭的擴展規(guī)范。
SOAP消息頭主要有如下幾個屬性。
1)role
在SOAP規(guī)范中,一條SOAP消息在到達最終目的地之前,可能會通過多個SOAP節(jié)點。每個SOAP節(jié)點都能接收和處理SOAP消息并將它轉發(fā)到下一個SOAP節(jié)點。通過設定role屬性,可以指明由哪個SOAP節(jié)點來處理SOAP消息頭。如果選擇默認的role屬性項,則表明SOAP消息頭將被定位至最終的SOAP節(jié)點。
2)mustUnderstand
該屬性指明接收消息的SOAP節(jié)點是否必須理解和處理SOAP消息頭。如果mustUnderstand=“false”,表明接收消息的SOAP節(jié)點可以忽略SOAP消息頭;如果mustUnderstand=“true”,表明接收消息的SOAP節(jié)點必須理解并處理SOAP消息頭,否則必須返回一個SOAP故障。
3)relay
當relay屬性值為“true”時,未被處理的SOAP消息頭必須被繼續(xù)發(fā)送。
3.SOAP消息體
SOAP消息體包含的是SOAP消息的實際負載,因此在SOAP消息中是必需元素。SOAP消息體由SOAP消息的最終接收方接收并處理。
SOAP消息體中的項可以包含一個可選的encodingStyle屬性,代表該項的編碼風格,如果消息體中的某項為自己定義了編碼風格屬性,那么該屬性將替代(override)在信封中定義的編碼風格。
SOAP消息體可以包含任意內容,但SOAP規(guī)范定義了兩種消息風格供發(fā)送者和接收者使用。這兩種消息風格分別被稱為RPC風格(RPC style)和文檔風格(document style)。SOAP消息體可以包含可選的SOAP故障。
RPC風格的消息遵從SOAP標準,封裝的是RPC調用的請求和返回消息,對該類消息的主要約束是必須把操作名稱作為封裝了對操作的調用請求和返回消息負載的根元素名稱,如圖2-5和代碼2-1(RPC風格的調用請求消息)、代碼2-2(RPC風格的返回消息)所示。一般RPC風格的消息可以由SOAP工具自動產生。而由文檔風格的消息封裝的XML文檔可以是消息發(fā)送方和消息接收方約定的任意格式。

圖2-5 RPC風格的調用請求消息和返回消息



4.SOAP故障
SOAP故障用于攜帶出錯信息,SOAP故障只能作為SOAP消息體的直接子元素出現(xiàn),且至多出現(xiàn)一次。
SOAP故障包含如下幾個子元素。
(1)Code(SOAP 1.1規(guī)范中為faultCode;SOAP 1.2規(guī)范中為Code):Code元素在故障元素中是必需的。Code元素中包含一個必需的Value子元素和一個可選的Subcode子元素。Value元素的可能取值為故障代碼;每個Subcode元素是迭代的,它由一個必需的Value子元素和一個可選的Subcode子元素組成。表2-1列出了SOAP 1.2規(guī)范中的故障代碼及其含義。
表2-1 SOAP 1.2規(guī)范中的故障代碼及其含義

(2)Reason(SOAP1.1規(guī)范中為faultString;SOAP1.2規(guī)范中為Reason):Reason元素在故障元素中是必需的,該元素不是為處理程序設定的,而是為故障代碼提供可以讀懂的故障解釋;Reason元素可以存在多個Text子元素。
(3)Node:Node元素在故障元素中也是可選的,它指明了在消息傳遞路徑中,哪個SOAP節(jié)點引發(fā)了故障。
(4)Role:Role元素在故障元素中是可選的,它指明了引發(fā)故障的SOAP節(jié)點的角色。
(5)Detail:Detail元素在故障元素中是可選的。在SOAP1.1規(guī)范中,如果SOAP消息體元素的內容無法被處理,那么就需要用到Detail元素,也就是說,Detail元素提供了與消息體元素相關的應用程序的故障信息;SOAP 1.2規(guī)范則不再區(qū)分是消息頭故障還是消息體故障。
2.1.1.4 SOAP消息編碼
SOAP信封及SOAP消息體中的元素都可以設定encodingStyle屬性,該屬性指明了SOAP消息的編碼風格,在信封中設定的編碼風格作用于整個SOAP消息體,而消息體包含的元素自己設定的編碼風格僅作用于自身的范圍。現(xiàn)在,SOAP規(guī)范并沒有限定encodingStyle屬性的取值,但常見的是SOAP編碼風格和字面(literal)編碼風格。所謂字面編碼就是沒有編碼風格(不設定encodingStyle屬性),SOAP消息的格式完全由交互雙方自行約定。而SOAP編碼風格的消息必須遵從SOAP編碼風格。
SOAP 1.1規(guī)范的第5部分定義了SOAP編碼風格。到SOAP 1.2規(guī)范時,SOAP編碼風格不再是SOAP規(guī)范的一部分,而是單獨成為一個可選規(guī)范。SOAP 1.2編碼風格的URI為http://www.w3.org/2003/05/soap-encoding,如果encodingStyle屬性被賦予該URI,則表明使用的是SOAP編碼風格。
SOAP編碼的原理:在SOAP模式的約束下,應用級對象(如Java對象、C#對象)基于SOAP數(shù)據(jù)模型規(guī)則被轉換為SOAP編碼的XML消息負載。在發(fā)送者和接收者不另行約定消息內容模式的情形下,它們可以使用SOAP編碼來實現(xiàn)從應用級對象到XML消息文檔的自動處理,在轉換過程中,程序設計語言的類型被轉換為XML Schema。
下面簡單介紹一下SOAP編碼是如何把程序設計語言的類型轉換為XML Schema的。程序設計語言的類型一般可以分為簡單類型和復合類型,簡單類型是無法包含其他元素的類型。
1.簡單類型的編碼
簡單類型都可以采用葉節(jié)點元素來表示,如代碼2-3所示。

程序設計語言中的枚舉類型直接對應XML Schema中的枚舉類型。代碼2-4給出的是Month枚舉類型。

2.復合類型的編碼
SOAP編碼提供了對結構(Structs)和數(shù)組(Arrays)兩種復合類型的編碼。結構允許把不同類型的值混合在一起,每個值用唯一的存儲器存儲和接收;數(shù)組由多個值組成,這些值用一個順序位置號存儲和檢索。
1)結構
在結構類型中,允許把不同類型的值混合在一起,但同一結構中的不同組成元素的名稱必須是唯一的。SOAP編碼把結構映射為XML Schema復合類型,如代碼2-5所示。

2)數(shù)組
數(shù)組采用順序位置來標識多個值。數(shù)組被定義為“soapEnv:Array”類型或從“soapEnv:Array”衍生的類型。數(shù)組表示元素值,對元素名沒有特別的約束。數(shù)組中包含的元素可以是簡單類型或復合類型,數(shù)組成員值也可以是數(shù)組。數(shù)組可以單引用或多引用。代碼2-6給出的是一個整型數(shù)組的片段示例。

代碼2-6中數(shù)組元素的類型也可以直接通過“soapEnv:arrayType”屬性來指明,如代碼2-7所示。

2.1.1.5 SOAP和網絡傳輸協(xié)議的綁定
SOAP消息可以和各種網絡傳輸協(xié)議綁定,如SOAP 1.0規(guī)范最初規(guī)定的HTTP協(xié)議,以及新SOAP規(guī)范和主流的SOAP供應商推出的SMTP、FTP、POP3、BEEP、JMS、MSMQ等協(xié)議。
由于當前幾乎所有的操作系統(tǒng)都支持HTTP,因此雖然HTTP綁定是可選的,幾乎所有SOAP實現(xiàn)方案都支持HTTP綁定,SOAP規(guī)范中也只對SOAP的HTTP綁定進行了詳細說明。
本節(jié)介紹如何實現(xiàn)SOAP的HTTP綁定,SOAP會遵守HTTP請求/響應消息交換模式,在HTTP請求中提供SOAP請求參數(shù),并且在HTTP響應中包含SOAP響應參數(shù)。
1.SOAP請求
根據(jù)SOAP Web方法(SOAP Web method)[1]的定義,在與HTTP等網絡傳輸協(xié)議進行綁定實現(xiàn)SOAP消息傳輸時,需要指出所使用的SOAP Web方法,如GET、POST等。GET方法通常被用來取得Web上的信息,POST方法則被用來將信息從客戶端傳送給服務器,然后利用POST方法所傳送的信息就會被服務器上的應用程序使用。利用GET方法只能傳送特定類型的信息,而利用POST方法則可以傳送各種類型的數(shù)據(jù)。
代碼2-8是用HTTP POST方法表示的SOAP請求。

在這個代碼中,第一行包含了三個不同的部分:請求的方法(POST)、請求的URI(/OrderStatus),以及使用協(xié)議的版本(HTTP/1.1)。
第二行是請求消息被傳送的目標服務器的地址。
第三行包含了媒體類型和字符編碼類型,text/xml表示負載是純文字形式的XML。當HTTP信息中包含SOAP數(shù)據(jù)主體時,HTTP應用程序必須遵循RFC 2376的內容型別text/xml。負載指的是被傳送的數(shù)據(jù)。SOAP要求必須使用text/xml作為媒體類型;SOAP使用utf-8作為字符編碼類型。
第四行則指定負載的大小,以位為單位。
第五行的SOAPAction在SOAP 1.2規(guī)范中是可選的,用來指定SOAP HTTP要求的目標。如果SOAP消息的接收節(jié)點希望在處理SOAP信封元素之前就能了解SOAP消息的一些確切信息,則可以通過HTTP綁定中的SOAPAction來實現(xiàn)。
2.SOAP響應
代碼2-9是代碼2-8中請求消息的HTTP響應。

代碼2-9的第一行包含了狀態(tài)碼(200)及與狀態(tài)碼相關聯(lián)的信息(OK)。SOAP HTTP完全遵循HTTP狀態(tài)碼的語法,主要包括如下幾種狀態(tài)碼。
(1)成功狀態(tài)碼。2XX HTTP成功狀態(tài)碼用來說明SOAP請求消息已經被接收或被成功處理。其中,200 OK表示請求消息被成功接收,并返回一個響應消息,該響應消息不是一個錯誤,而是一個正常的SOAP響應;202 Accepted表示請求消息被成功接收和處理,但不會返回響應消息。
(2)錯誤狀態(tài)碼。通常情況下,HTTP使用4XX表示SOAP消息傳送中在客戶端出現(xiàn)的錯誤,使用5XX表示在服務器端出現(xiàn)的錯誤。其中,400 Bad Request表示HTTP請求或SOAP消息中的XML文檔格式錯誤;405 Method Not Allowed表示服務提供者不支持請求消息中選用的Web方法;415 Unsupported Media Type表示服務提供者不支持HTTP POST消息中Content-Type選用的值。500 Internal Server Error表示服務器內部錯誤,或者SOAP響應消息包含了SOAP故障元素。
(3)3XX Redirection。它表示請求的資源被遷移了,需要使用傳回的相關聯(lián)的Location頭字段的URI值重試請求。