SOAP淨化有線協議(一):SOAP基礎知識

來源:互聯網
上載者:User
 許多開發人員都遇到過這樣的情形:一個CORBA客戶程式需要獲得分散式元件物件模型(DCOM)客戶程式的服務,或者相反。常見的解決方案是使用一個
COM/CORBA橋。然而,這種解決方案存在許多問題。假設在兩個已經很複雜的系統之間(CORBA
ORB和COM之間)引入了一個新的軟體,在CORBA的Internet Inter-ORB
Protocol(IIOP)到DCOM的Object Remote Procedure
Call(ORPC)之間,繁雜的雙向轉換將使得中間起橋接作用的軟體變得很複雜。任何對IIOP協議和ORPC協議的修改都導致修改橋接軟體。如果我說
SOAP能夠緩解這個問題,你會怎麼想呢?感興趣嗎?

SOAP的全稱是Simple Object Access
Protocol,即簡易物件存取通訊協定 (SOAP)。簡單地說,SOAP是一種有線協議,類似於CORBA的IIOP、DCOM的ORPC或Java遠程方法調用的
Java遠程方法協議(Java Remote Method
Protocol,JRMP)。你也許會懷疑,既然已經有了那麼多有線協議,為什麼我們還需要另外一種?事實上,這不正好導致前面所討論的問題嗎?這些問
題都有道理,但是,SOAP和其他有線協議有所不同。

我們來分析一下:

  • IIOP、ORPC和JRMP都是二進位協議,而SOAP則是一種使用XML的以文本為基礎的協議。利用XML進行資料編碼
    為SOAP帶來一些獨一無二的功能。例如,調試以SOAP為基礎的應用程式更容易,因為閱讀XML要比閱讀位元據容易得多。另外,由於所有的SOAP
    訊息都是文字格式設定,和IIOP、ORPC或者JRMP相比,SOAP更容易和防火牆協作。
  • SOAP
    協議以非供應商私人的協議為基礎,即XML、HTTP和Simple Mail Transfer
    Protocol(SMTP),所有供應商都可以使用SOAP協議。例如,Microsoft和各個CORBA
    ORB供應商(例如Iona)一樣,已經承諾支援SOAP。IBM在建立SOAP協議的過程中起到了重要的作用,它也為Java程式員建立了一個優秀的
    SOAP工具包。該公司已經把工具包捐贈給Apache Software Foundation的XML
    Project,後者以該軟體包為基礎,構造出了Apache-SOAP實現。這個實現在Apache許可之下免費提供給使用者。再返回來看本文開頭提出的
    問題,如果DCOM使用SOAP,ORB供應商也使用了SOAP,那麼,COM/CORBA協同操作中出現的問題將變得不值一提。

SOAP決不只是一個漂亮的口號,它是一種即將深入滲透到未來分散式運算的技術。人們希望,SOAP結合其他技術,比如UDDI(Universal
Discovery Description, and Integration)和WSDL(Web Services Description
Language),在Web服務這一概念的支援下,改變未來商業應用跨越Web進行通訊的方法。我甚至無法充分地表達出在開發人員的工具包中加上SOAP
知識的重要程度。這是一個關於SOAP的系列文章,總共四篇。這是第一篇,介紹一些基礎知識。我們將從SOAP這一思想的構思說起。

一、SOAP簡介
如前所述,SOAP用XML作為資料編碼格式。用XML作為資料編碼格式並非SOAP的原創,實際上這是一種相當自然的選擇。XML-RPC和ebXML也同樣使用XML。要瞭解這方面的更多資訊,請參見本文最後的“參考資源”。

請考慮下面的Java介面:

Listing 1

public interface Hello
{
public String sayHelloTo(String name);
}

客戶程式在調用sayHelloTo()方法時提供了一個名字,它希望從伺服器接收到一則個人化的“Hello”資訊。現在,假定RMI、CORBA和
DCOM都不存在,開發人員必須負責序列化方法調用,並把訊息發送給遠程機器。幾乎所有的人都會說“這該使用XML”,我同意。因此,讓我們先從對伺服器的
請求格式開始。假設要類比sayHelloTo("John")調用,我打算髮送的請求是:

Listing 2

<?xml version="1.0"?>
<Hello>
<sayHelloTo>
<name>John</name>
</sayHelloTo>
</Hello>

在這裡,我把介面的名字作為根結點。另外,我還把方法名字和參數名字都當作節點。接下來,我們要把這個請求發送給伺服器。我們不建立自己的TCP/IP消
息,而是使用HTTP。因此,下面的步驟應該是把請求封裝成HTTP POST請求格式,然後把它發送給伺服器。實際建立該HTTP
POST請求的詳細過程在本文後面介紹,現在,我們先假定它已經建立完畢。伺服器接收到了這個請求,解碼XML,然後再以XML格式向客戶程式發送應答。
假設應答內容如下:

Listing 3

<?xml version="1.0"?>
<Hello>
<sayHelloToResponse>
<message>Hello John, How are you?</message>
</sayHelloToResponse>
</Hello>

根節點仍然是介面的名字Hello。但這一次,原來對應著方法的節點名字不再是sayHelloTo,而是方法的名字加上“Response”字串。客
戶程式知道自己調用了哪一個方法,要找出被呼叫者法的傳回值,它只需查看名字為方法名字加上“Response”字串的元素。

以上就是SOAP的根本思路。Listing 4顯示了同一請求用SOAP XML編碼之後的結果:

Listing 4

<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Header>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:sayHelloTo
xmlns:ns1="Hello"
SOAP-ENV:encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/">
<name xsi:type="xsd:string">John</name>
</ns1:sayHelloTo>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

看起來稍微複雜了一點,對吧?實際上,它和我們前面編寫的請求類似,只是略微擴充了一些東西。首先,注意SOAP文檔通過一個Envelope(根節
點)、一個Header區、一個Body區,整潔地組織到一起。Header區用來封裝那些與方法本身無直接關係的資料,提供環境方面的資訊,比如事務
ID和安全資訊。Body區包含面向方法本身的資訊。在Listing 2中,我們自己編寫的XML只包含一個Body區。

第二,注意Listing
4大量地應用了XML名稱空間。SOAP-ENV映射到名稱空間http://schemas.xmlsoap.org/soap/envelope
/,xsi映射到http://www.w3.org/1999/XMLSchema-instance,而xsd映射到http:
//www.w3.org/1999/XMLSchema。這三者是所有SOAP文檔都擁有的標準名稱空間。

最後,在Listing 4中,介面名稱(即Hello)不再象在Listing
2中那樣成為節點的名字;相反,它引用了一個名稱空間nsl。另外,參數的類型資訊也隨同參數的值一起發送給了伺服器。注意信封
(Envelope)encodingStyle屬性的值。這個屬性值設定成了http://schemas.xmlsoap.org/soap
/encoding/。這個值告訴伺服器用來編碼(即序列化)方法的編碼方式;伺服器需要這個資訊,以便正確地解除方法的序列化。對於伺服器來
說,SOAP文檔的自我描述能力是相當完善的。

對於上面的SOAP請求,伺服器的應答如下:

Listing 5

<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-nstance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:sayHelloToResponse
xmlns:ns1="Hello"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:string">Hello John, How are you doing?</return>
</ns1:sayHelloToResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Listing 5與Listing
4的請求訊息類似。在上面的代碼中,傳回值(即個人化的“Hello”訊息)包含在Body區。SOAP訊息文檔的格式非常靈活。例如,編碼方式不固定,
而是由客戶程式指定。只要是客戶程式和伺服器都認可的編碼方式,可以是任何合法的XML文檔。

另外,分離調用環境資訊意味著方法本身並不關心這類資訊。在當前的市場上,主流應用伺服器都遵從這一理念。早先,我曾經指出環境資訊可以包含事務和安全方面的資訊。事實上,環境可以涵蓋幾乎所有的東西。下面是一個SOAP訊息頭的例子,它帶有一些事務方面的資訊:

Listing 6

<SOAP-ENV:Header>
<t:Transaction xmlns:t="some-URI" SOAP-ENV:mustUnderstand="1">
5
</t:Transaction>
</SOAP-ENV:Header>

名稱空間t映射到了與特定應用有關的URI。這裡的5表示的是該方法從屬於其中的事務ID。注意SOAP信封mustUnderstand屬性的應用。這
個屬性被設定成了1,它表示伺服器要麼理解並按照要求處理該事務請求,要麼表示無法處理該請求;這是SOAP規範所要求的。

二、錯誤處理
使用SOAP並不意味著任何時候所有的請求都會獲得成功。許多地方可能會出現差錯。例如,伺服器可能無法訪問某個關鍵性的資源(比如資料庫),因而無法順利地處理請求。

讓我們返回“Hello”執行個體,為它加上一個假想的約束,即“在星期二向別人說Hello不合法。”因此,星期二的時候,即使發送給伺服器的請求是合法的,伺服器也會把一個錯誤資訊返回給用戶端。應答內容將如下所示:

Listing 7

<SOAP-ENV:Envelope xmlns:SOAP-ENV="
http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring>Server Error</faultstring>
<detail>
<e:myfaultdetails xmlns:e="Hello">
<message>
Sorry, my silly constraint says that I cannot say hello on Tuesday.
</message>
<errorcode>
1001
</errorcode>
</e:myfaultdetails>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

我們來分析一下http://schemas.xmlsoap.org/soap/envelope/名稱空間定義的Fault元素。Fault元素總是
Body元素的直接子項目,所有的SOAP伺服器必須始終通過該元素報告所有錯誤情況。Fault元素必須包含faultcode和
faultstring元素,不能有例外。faultcode是一個能夠標識問題的代碼;客戶程式按照SOAP規範的要求利用faultcode進行演算法
處理。SOAP規範定義了一小組錯誤碼供使用者使用。另一方面,faultstring是供人類閱讀的錯誤資訊。

Listing
7的代碼還包含了一個detail元素。由於錯誤在處理SOAP訊息的Body區時出現,detail元素必須出現。正如你將在本文後面看到的,如果錯誤
在處理Header區時出現,detail元素不應出現。在Listing
7中,應用利用detail元素提供當前錯誤更詳細、更自然的解釋,即星期二不允許說Hello。SOAP還提供另外一個面向具體應用的錯誤碼,即半可
選的faultfactor元素,但上面的錯誤資訊中沒有顯示這個元素。之所以稱這個元素是半可選的,是因為如果錯誤訊息不是由請求最終處理點的伺服器發
送,即由一個中間伺服器發送,則錯誤訊息必須包含該元素。SOAP對faultcode元素不應出現的情形沒有作任何規定。

在Listing 7中,錯誤起源於方法調用本身,處理該方法的應用導致了這個錯誤。現在,我們來看一下另一種類型的錯誤,這種錯誤由於伺服器不能處理要求標頭資訊而導致。舉例來說,假設所有的Hello訊息必須在一個事務環境之內產生,則請求類似於:

Listing 8

<SOAP-ENV:Envelope
xmlns:SOAP-ENV="
http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="
http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Header>
<t:Transaction xmlns:t="some-URI"
SOAP-ENV:mustUnderstand="1">
5
</t:Transaction>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:sayHelloTo
xmlns:ns1="Hello"
SOAP-ENV:encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/">
<name xsi:type="xsd:string">Tarak</name>
</ns1:sayHelloTo>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

上面訊息的Header區包含一個transaction元素,它指定了方法調用必須從屬於其中的事務編號。這裡我說“必須”是因為
transaction元素使用了mustUnderstand屬性。如前所述,SOAP伺服器要麼遵照屬性的指示處理請求,要麼聲明不能處理請求。假定
SOAP伺服器不能處理,它必須返回一個錯誤資訊。這時的應答應該類似於:

Listing 9

<SOAP-ENV:Envelope xmlns:SOAP-ENV="
http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:MustUnderstand</faultcode>
<faultstring>SOAP Must Understand
Error</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

上面的代碼類似Listing
7顯示的錯誤資訊。但應該注意的是,detail元素不再出現。正如我在前面指出的:SOAP規範規定,如果錯誤在處理Header區的時候出現,則錯誤
訊息中不應包含detail元素。事實上,我們可以根據detail元素是否出現,迅速判定錯誤是在處理Body區還是在處理Header區時出現。

三、SOAP與HTTP
在第一個例子中,我通過HTTP把定製的XML請求發送給伺服器,但沒有詳細介紹這麼做涉及到了哪些操作。現在我們回過頭來看那個問題。怎樣才能把一個
SOAP請求(而不是定製的XML)通過HTTP發送給伺服器?SOAP很自然地遵循了HTTP的請求/應答訊息模型。這個模型在HTTP請求中提供
SOAP請求參數,在HTTP應答中提供SOAP應答參數。實際上,SOAP 1.0特別指明HTTP作為它的傳輸協議。SOAP
1.1略有放鬆。雖然SOAP
1.1仍舊可以使用HTTP,但它也可以使用其他協議,比如SMTP。在這個系列的文章中,我只討論通過HTTP使用SOAP的情形。

讓我們返回Hello樣本。如果我們通過HTTP把SOAP請求發送給伺服器,則代碼應該類似於:

Listing 10

POST http://www.SmartHello.com/HelloApplication HTTP/1.0
Content-Type: text/xml; charset="utf-8"
Content-Length: 587
SOAPAction: "http://www.SmartHello.com/HelloApplication#sayHelloTo"
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="
http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="
http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Header>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:sayHelloTo
xmlns:ns1="Hello"
SOAP-ENV:encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/">
<name xsi:type="xsd:string">Tarak</name>
</ns1:sayHelloTo>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

 

Listing 10代表的SOAP請求與Listing 4的請求基本相同,但Listing
10的開頭加入了一些HTTP特有的代碼。第一行代碼錶明這是一個遵循HTTP
1.1規範的POST請求,POST的目標是http://www.SmartHello.com/HelloApplication。下一行指示內容的
類型,在HTTP訊息中包含SOAP實體時,內容類型必須是text/xml。Content-Length指明了POST請求有效載荷的長度。

第四行是SOAP特有的,而且它是必不可少的。SOAPAction HTTP要求標頭指明了SOAP HTTP請求的目標,它的值是一個標識目標的URI。SOAP不對該URI的格式作任何限制,實際上,這個URI甚至不必對應某個實際的位置。

SOAPAction的一個可能的應用是,防火牆檢查該要求標頭的值,決定是否允許請求通過防火牆。

一旦伺服器處理完請求,它將向客戶返回一個應答。應答的內容如Listing 11所示(假設沒有出現錯誤):

Listing 11

HTTP/1.0 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: 615
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="
http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="
http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:sayHelloToResponse
xmlns:ns1="Hello"
SOAP-ENV:encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:string">Hello John, How are
you doing?</return>
</ns1:sayHelloToResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

 

 

這個SOAP應答與Listing
5所顯示的一樣,但前面加上了一些HTTP特有的代碼。由於沒有出現錯誤,第一行代碼顯示應答狀態是200。在HTTP協議中,200應答狀態碼表示“
一切正常”。如果在處理SOAP訊息(Header區或者Body區)的時候出現了任何錯誤,則返回的狀態碼將是500。在HTTP中,500狀態碼
表示“internal server error”。此時,上述SOAP應答的第一行代碼將是:

HTTP 500 Internal Server Error

四、HTTP擴充架構
許多應用對服務的需求超過了傳統HTTP提供的服務。其結果就是,這類應用擴充了傳統的HTTP協議。然而,這種擴充是應用本身私人的。HTTP擴充架構
試圖確立一個通用的HTTP擴充機制,從而解決這個問題。HTTP擴充架構的擴充之一是增加了一個M-POST方法,其中的M表示Mandatory(必
須遵循的,強制的)。如果一個HTTP請求包含至少一個強制的擴充聲明,那麼這個請求就稱為強制的請求。引入強制的擴充聲明通過Man或者C-Man頭進
行。強制請求的要求方法名字必須帶有“M-”首碼,例如,強制的POST方法稱為M-POST。

SOAP 1.0要求客戶程式首先發送一個HTTP POST請求,只有當伺服器返回錯誤510時才發送M-POST請求。SOAP
1.1不再對客戶作這種限制,也就是說,SOAP
1.1允許客戶從發送任何一種類型的請求開始。下面的請求就是迄今為止我們一直在討論的那個請求,但它現在是M-POST格式:

Listing 12

M-POST http://www.SmartHello.com/HelloApplication HTTP/1.1
Content-Type: text/xml; charset="utf-8"
Content-Length: 587
Man: "http://schemas.xmlsoap.org/soap/envelope/"; ns=01
01-SOAPAction: "http://www.SmartHello.com/HelloApplication#sayHelloTo"
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="
http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="
http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Header>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:sayHelloTo
xmlns:ns1="Hello"
SOAP-ENV:encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/">
<name xsi:type="xsd:string">Tarak</name>
</ns1:sayHelloTo>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

對於實際的SOAP訊息來說,Listing 12和Listing
10沒有什麼不同。但要求標頭中有一些不同的地方,例如,現在我們發出的不是POST請求,而是一個M-POST請求。正如前面所介紹的,象M-POST這
樣的強制請求至少有一個強制擴充聲明。這裡我們就有一個:Man域描述了一個強制性的端到端擴充聲明,把頭首碼01映射到了名稱空間
http://schemas.xmlsoap.org/soap/envelope/。請注意這個首碼關聯到SOAPAction域的方式。

一旦伺服器處理完該請求,它將返回一個應答給客戶。應答內容類別如(假設沒有出現錯誤):

Listing 13

HTTP/1.0 200 OK
Ext:
Content-Type: text/xml; charset="utf-8"
Content-Length: 615
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="
http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="
http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:sayHelloToResponse
xmlns:ns1="Hello"
SOAP-ENV:encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:string">Hello John, How are
you doing?</return>
</ns1:sayHelloToResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

同樣地,Listing 13顯示的應答類似於對普通POST請求的應答(如Listing 11所示),兩者的不同之處在於Ext域。

在通過HTTP使用SOAP的過程中,我們欣喜地看到,實際的SOAP訊息(SOAP信封和它裡面的所有內容)總是保持不變,就如訊息尚未載入HTTP協
議時一樣。根據這一事實可以推斷出,HTTP不是能夠與SOAP協作的唯一協議。例如,SOAP可以方便地和SMTP協議或者其他定製的私人協議一起運
行。唯一的要求是兩者——用戶端和伺服器端——都理解該協議。

五、SOAP的特點:簡單
至此為止,我們討論了SOAP定義的方方面面,但有許多領域的問題SOAP沒有定義。SOAP規範的創立者明確地排除了一些關係密切的領域,比如構造物件模型,還有其他許多已經確立的標準。

造成這種現象的原因可以從分析SOAP的目標理解。SOAP的目標除了擴充性之外,另一個主要的設計目標是簡單。為了保持SOAP簡單,SOAP規範的創
立者決定,只定義那些對於建立一個輕型協議來說絕對必須的東西。例如,SOAP沒有定義/指定任何有關分布式垃圾收集、型別安全或版本控制、雙向HTTP
通訊、訊息盒(Message-box)運輸或管道處理、對象啟用等方面的內容。SOAP的目標就是成為一種簡單的協議——一種在任何作業系統上,單個開
發者能夠用任何語言化數天時間實現的協議。考慮到這一點,SOAP在許多方面沒有作出明確定義實際上是一件好事,因為在構造分布式系統時,所有現有的技術
都可以方便地採用SOAP,即使不同技術之間的差異象CORBA和DCOM的差異那樣明顯。

■ 結束語
在這篇文章中,我介紹了SOAP的一些基本概念,以及它之所以如此設計的一些原因。然而,相對於SOAP這座冰山來說,這隻是它的一角。要查看有關
SOAP的更多資訊,請查閱參考資源部分給出的SOAP規範連結。隨著本系列文章的展開,我將在這裡介紹有關SOAP規範所有你必須瞭解的知識。

在第二部分中,我將介紹Apache的SOAP實現。我們將使用該實現,建立一個利用SOAP作為有線協議的簡單分布式應用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.