<menu id="ocigx"><listing id="ocigx"><em id="ocigx"></em></listing></menu><em id="ocigx"><track id="ocigx"><strong id="ocigx"></strong></track></em>
<ins id="ocigx"></ins>

<samp id="ocigx"></samp>

<mark id="ocigx"><ruby id="ocigx"><legend id="ocigx"></legend></ruby></mark><bdo id="ocigx"></bdo>
      <kbd id="ocigx"></kbd>
      首頁 > 開發 > 綜合 > 正文

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

      2020-02-03 15:08:22
      字體:
      來源:轉載
      供稿:網友
      一、soap簡介
      如前所述,soap用xml作為數據編碼格式。用xml作為數據編碼格式并非soap的原創,實際上這是一種相當自然的選擇。xml-rpc和ebxml也同樣使用xml。要了解這方面的更多信息,請參見本文最后的“參考資源”。

      請考慮下面的java接口:

      listing 1

      public interface hello
      {
      public string sayhelloto(string name);
      }
      客戶程序在調用sayhelloto()方法時提供了一個名字,它希望從服務器接收到一則個性化的“hello”信息?,F在,假定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中,錯誤起源于方法調用本身,處理該方法的應用導致了這個錯誤?,F在,我們來看一下另一種類型的錯誤,這種錯誤由于服務器不能處理請求頭信息而導致。舉例來說,假設所有的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請求發送給服務器,但沒有詳細介紹這么做涉及到了哪些操作?,F在我們回過頭來看那個問題。怎樣才能把一個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的差異那樣明顯。國內最大的酷站演示中心!
      發表評論 共有條評論
      用戶名: 密碼:
      驗證碼: 匿名發表