簡單對象訪問協議(SOAP)

摘自

http://www-128.ibm.com/developerworks/cn/webservices/ws-intwsdl/part2/index.html

使用 WSDL 部署 Web 服務,第 2 部分: 簡單對象訪問協議(SOAP)

Web 服務和 WSDL 簡介

級別: 初級

Bilal Siddiqui, CEO

2002 年 3 月 01 日

簡單對象訪問協議(SOAP)提供對遠程對象的訪問。這些對象的示例是簡單的 JavaBeans 組件或是企業 JavaBeans 組件和 COM/COM+ 對象等。這些對象駐留在不同企業內部並且可能存在於因特網的任何位置。因此,SOAP 通過因特網通信並且是一種在不同企業間交換信息的機制。在本文中,Bial 會詳細的討論 SOAP 通信,對象是怎樣用 SOAP 公開其功能的,怎樣調用 SOAP 對象,怎樣在有 SOAP 意識的應用程序間交換信息。他還會展示第 1 部分中提到的 WSDL 應用程序的 SOAP 服務部署,以及遠程服務器對它的調用。

SOAP 和 WSDL

我在本系列文章的 第 1 部分介紹了 WSDL。WSDL 描述了 Web 服務的接口。Web 服務所有者將用 SOAP 來實現他們的接口。因此, WSDL 服務實際上作爲 SOAP 服務一樣存在。一旦 Web 服務用戶擁有 WSDL 文件,他或者她就知曉接口的細節。他或者她就會用 SOAP 來與 Web 服務通信。

可以把 Web 服務考慮爲對象,可以通過 WSDL 接口公開並且使用 SOAP 通過因特網遠程訪問。既然服務是對象,那麼肯定有每種服務的相關屬性和每種服務調用的行爲。SOAP 消息是 XML 文檔,可通過 HTTP 工作。

爲什麼用 SOAP?

B2B(Business-to-business)和 A2A(application-to-application )需求表明企業之間爲交換信息而相互通信。這種概念被用在 B2B、工作流和跨企業集成中。例如,設想一條垂直供應鏈,在鏈上一家企業爲了滿足它的客戶需求而需要調用其提供者的服務。而一些提供者需要沿供應鏈進一步下行來調用其它企業的服務。

很明顯,在此應用程序中互操作性是最爲重要的。任何單個企業只能實現 SOAP 通信通道的一端。另一端將是因特網上 任何地方的實體

在最近幾年裏,企業之間的集成和互操作性已經成爲軟件工程師和企業的一個挑戰性任務。平臺相關性也成爲取得集成和互操作性的一個大問題。SOAP 依然是在企業間取得集成和互操作性最簡單的機制。

 


 

SOAP 體系結構

有了對 SOAP 和它的用途的基本理解,我現在就展開對其體系結構的討論以瞭解一些深層知識。請參閱 圖 1, 在此圖裏面您可以識別典型 SOAP 通信體系結構中的一些組件:

  1. SOAP 客戶機
  2. SOAP 服務器
  3. 實際服務


圖 1. 一個典型 SOAP 通信體系結構的組件
一個典型 SOAP 通信體系結構的組件

讓我解釋上面所提到的每個實體的體系結構角色。下面的討論參照 圖 1

SOAP 客戶機

SOAP 客戶機是一臺有 SOAP 機制的機器,它可以產生 SOAP 請求並通過 HTTP 發送到服務器。一條 SOAP 請求是一種類型的 SOAP 消息,通常只有兩種類型的 SOAP 消息:一條 SOAP 請求就是一臺 SOAP 客戶機發送給 SOAP 服務器的內容,一條 SOAP 響應就是 SOAP 服務器對 SOAP 客戶機響應的內容。 清單 1是典型的 SOAP 請求,請參閱 清單 2來回顧 SOAP 響應。

清單 1:一條簡單的 SOAP 請求


SOAP 服務器

SOAP 服務器也是一臺有 SOAP 機制的機器,能夠接收來自 SOAP 客戶機的請求,並對之作出適當的響應。這些編過碼的響應會返回發出請求的 SOAP 客戶機。在 SOAP 服務器內部有三個實體:

  1. 服務管理器
  2. 被部署服務的列表
  3. XML 轉換程序

服務管理器負責根據請求管理服務。請參閱 清單 1 的服務請求,在這裏元素 <m:getListOfModels xmlns:m="urn:MobilePhoneservice" > 包含了服務的名稱。服務管理器會讀取 SOAP 客戶機想調用的 SOAP 服務的名稱並檢查所需的服務實際上是否駐留於這臺 SOAP 服務器上。此後,它會查詢被部署服務的列表(SOAP 服務器所託管的所有服務的列表)。若存在,服務管理器將把 SOAP 請求傳送給 XML 轉換程序。XML 轉換程序就負責將 SOAP 請求的 XML 結構轉換成程序員用來實現實際服務的編程語言(例如,Java 編程語言)的結構。還要負責將來自實際服務的響應轉換回 SOAP 響應的 XML 結構。請參閱 清單 2獲得 SOAP 響應的說明。

清單 2:一條簡單的 SOAP 響應


實際服務

圖 1中標有 actual service的框就是實際服務駐留的位置。服務實現可以是:例如,COM 組件或 JavaBeans 組件的形式。XML 轉換程序負責將 XML 結構轉換成合適的方法調用。當 XML 轉換程序調用了實際服務實現的某個方法時,這個方法就會完成它的工作並且將結果信息返回 XML 轉換程序。

請看一看 圖 1中連接 XML translator 和 actual service 的箭頭。箭頭的兩端同在一個企業內,這意味着同一個組織控制着通信兩端的接口。與穿過企業邊界的在 SOAP 客戶機和 SOAP 服務器之間的箭頭相比,這正是 SOAP 的目的所在。

 


 

SOAP 請求響應機制

當 SOAP 客戶機向 SOAP 服務器發送 SOAP 消息時,用 HTTP 協議傳輸。這就叫做 SOAP 與 HTTP 綁定。當 SOAP 服務器收到消息時,將消息交給服務管理器。服務管理器檢查被部署服務的列表,查找在 SOAP 消息中所需的服務。若沒有查找到所請求的服務,它將請求失敗返回給 SOAP 客戶機。但是若此項服務可以提供,控制權由服務管理器轉移給 XML 轉換程序(轉換程序完成合適語言的轉換並訪問實際服務實現)。服務實現會處理請求並將結果返回給 XML 轉換程序。XML 轉換程序將結果轉換成 SOAP 客戶機能夠理解的 SOAP 響應(XML 文檔)。然後又一次用 HTTP 綁定來傳輸 SOAP 響應。現在讓我們看一下 SOAP 與 HTTP 的綁定細節。

 


 

SOAP 與 HTTP 綁定

當您將 SOAP 和 HTTP 綁定在一起或在 HTTP 上操作 SOAP 時,您實際上將 HTTP 報頭加到了 SOAP 請求和響應上了。 清單 1是典型 SOAP 請求的結構,而清單 3456都是完整的 HTTP 請求,用來演示如何將 HTTP 報頭添加到 清單 1上。相似地, 清單 7是一條完整的 HTTP 響應,針對於來自 清單 2的 SOAP 響應。

無論您何時在 HTTP 上使用 SOAP,Content-Type 字段必須是 text/xml。現在您可以察看 清單 3清單 7的詳情。

使用 HTTP 的 SOAP 請求

您可以將 SOAP 和 HTTP 的 POST請求方法連用。爲了發送一條 SOAP HTTP 請求,您需要在 HTTP 中提供一個  SOAPAction 報頭字段。 SOAPAction 指定了 SOAP 請求的目的。服務器(例如過濾 HTTP 中 SOAP 請求消息的防火牆)可以用字段 SOAPAction 的值來做決定。

HTTP 客戶機在發送一條 SOAP HTTP 請求時必須用此報頭字段。SOAPAction 可以有如下幾種值:SOAPAction:"URI-Reference"
SOAPAction:"filename"
SOAPAction:""
SOAPAction:


清單 3:演示 SOAPAction 報頭字段中的 URI 引用


清單 3 在 SOAPAction 中包括如下 URI 引用: www.mobilephoneservice.com/Vendors/MobilePhoneservice#getListOfModels

這個 SOAPAction 展示了兩部分內容。第一部分是一個特別 SOAP 部署的地址: www.mobilephoneservice.com/Vendors/MobilePhoneservice

第二部分是一個片段標識符,它給出了我們感興趣的方法的名字(#getListOfModels)。


清單 4:演示 SOAPAction 報頭字段中的一個文件名


清單 4 在 SOAPAction 中包含一個文件名( MobilePhoneservice#getListOfModels )。 MobilePhoneservice 文件必須出現在主機 URI( www.mobilephoneservice.com/Vendors )中。 這個主機 URI 是在 HTTP 報頭中 host 字段( www.mobilephoneservice.com )和文件夾名( /Vendors )的結合。


清單 5:演示 SOAPAction 報頭中的空字符串


清單 5 在 SOAPAction 中包含一個空字符串("")。空字符串值表明 SOAP 的目的和 Host URI( www.mobilephoneservice.com/Vendors )的目的是一樣的。


清單 6:演示無值 SOAPAction 報頭


清單 6沒有包含 SOAPAction 值。這表明沒有關於消息目的的信息。

用 HTTP 的 SOAP 響應

響應將可能是兩種類型的 SOAP 響應中的一種:

  • 一個成功的 SOAP 操作產生 SOAP 結果
  • 一個不成功的 SOAP 操作產生一條 SOAP 錯誤消息


清單 7:一條帶有 HTTP 報頭的成功 SOAP 響應


清單 7是第一種情況,在此可以從 SOAP 服務器取得有意義的結果。

清單 8是一條典型的 SOAP 錯誤消息。SOAP HTTP 響應遵循 HTTP 中通信狀態信息的 HTTP 狀態碼的語義。若在處理一條請求時發生一個 SOAP 錯誤,SOAP HTTP 服務器必須發出一條 HTTP 500 "Internal Server Error" 響應,同時在響應中包括一條帶有 SOAP 出錯元素的 SOAP 消息。


清單 8:一條帶有 HTTP 報頭的典型 SOAP 錯誤消息



 

使用電子郵件的 SOAP

HTTP 不是唯一綁定 SOAP 消息的解決方案。若 HTTP 不合適,您可以用諸如 SMTP 的其它機制來用於 SOAP 綁定。將 SOAP 和 SMTP 綁定,您可以建立一條單向傳輸路由。兩條單向消息可以用來建立請求/響應通信。 用 SMTP 來發送一條 SOAP 消息,您需要遵從以下步驟:

  • 使用 MIME-Version 報頭字段
    MIME-Version用一個版本號來區別不同的 MIME 版本。它應用郵件處理代理(例如一個 POP 服務器)來區別舊版本和新版本所生成的郵件消息。請參閱 清單 9,它使用了一個 MIME-Version 報頭字段。

    清單 9:一個使用電子郵件的 SOAP 示例


  • 使用 Content-Type 報頭字段:
    Content-Type用來標識消息主體中的數據類型。對於 SOAP 消息 Content-Type 應該有一個值“text/xml”。請參閱 清單 9,它使用了 Content-Type。
  • 使用 Content-Transfer-Encoding 字段:
    Content-Transfer-Encoding 用來指定傳輸編碼的類型,也就是您所要傳輸的數據是字符格式還是二進制格式。 清單 9使用 Quoted-Printable 編碼,這種編碼符合依照 ASCII 字符集的可打印字符。這種對數據的編碼方式使郵件傳輸代理不可能修改結果八位元。請參閱 清單 9,它使用了 Content-Transfer-Encoding 。

 


 

SOAP 模式與實現

SOAP 消息

一條 SOAP 消息只是一個 XML 文檔,由一個強制性的 SOAP Envelope 組成,SOAP Envelope 有一個可選的 SOAP Header 和一個必須有的 SOAP Body。

SOAP 模式的元素:

  • Envelope
  • Header
  • Body
  • Fault

Envelope:
Envelope 是表示一條 SOAP 消息的頂層元素。爲了發送一條 SOAP 消息,必須包括此元素。Envelope 使用必要的 SOAP 名稱空間標識符( http://schemas.xmlsoap.org/soap/envelope/ )。若 Envelope 包含了錯誤的名稱空間,會產生一個關於 Envelope 名稱空間版本的錯誤。 清單 10是一個空 Envelope。稱其爲“空 Envelope”是爲了強調在通過“投遞”發出它之前,它最終應該包含一封“信”(也許是商業信)。SOAP 模式中的“信”就是指“SOAP Body”,HTTP POST(在 HTTP 與 SOAP 的綁定一部分討論過)就是傳輸機制。


清單 10:一個空 SOAP Envelope

Header:
SOAP Header 是可選的。您可以直接將 SOAP Body 放到 SOAP Envelope 中並完全忽略報頭。報頭提供了一個擴展 SOAP 消息功能的機制。例如,認證就是由 SOAP Header 條目所提供的一種典型擴展。在此情況下,將有一個認證框架,它會使用 SOAP 作爲更低級別的傳輸。請參閱 清單 11來查看在 SOAP 中的報頭實現。


清單 11:在一個 SOAP Envelope 中的報頭實現

Body:
Body 元素包含您實際要發送的消息。它是一個強制性的元素且其子元素通常屬於一個用戶定義的名稱空間。 清單 12 展示了一條引用一個用戶定義的名稱空間 “u” 的 SOAP 消息。Body 元素是必要信息的容器。這個元素必須在 SOAP 消息中出現並且必須是 SOAP Envelope 元素的一個直接子元素。它也必須直接跟在 SOAP Header 元素的後面。若沒有 Header 元素,那麼它應直接跟在 Envelope 元素的後面。主體可以包含子元素並且子元素可能是受限於名稱空間的。


清單 12: SOAP Envelope 內有 Header,還有 Body

Fault:
這個元素表明一條錯誤消息。它應作爲一個主體條目出現並且不能在 Body 元素中出現一次以上。通常,Fault 元素會在一條 SOAP 響應消息中出現,以表明在 SOAP 請求中出現錯誤。

Fault 的子元素:

  • faultcode (錯誤的標識)
  • faultstring (錯誤的描述)
  • faultactor (標識由誰導致的錯誤)
  • detail (錯誤細節。通常是一個應用程序特定錯誤,也就是說,它相當於在 SOAP 請求主體中用到地用戶定義的名稱空間)

清單 13是一條典型的錯誤消息。


清單 13: 當應用程序出現錯誤時,SOAP Fault 的使用



 

來自第 1 部分的一條對 WSDL 文件的 SOAP 請求

已經解釋了 SOAP 消息(請求和響應)的常規語法,我將展示如何對本系列 第 1 部分中的 MobilePhoneservice 開發一條 SOAP 請求。在第 1 部分中您設計一個完整的 WSDL 接口來解釋 MobilPhoneservice。移動公司在 MobilePhoneservice 中提供了兩種方法,一種是 getListOfModels() ,另一種是 getPrice(modelNumber)GetListOfModels() 沒有參數但是返回手機型號的一張列表,而 getPrice(modelNumber) 有一個參數 modelNumber 並返回需求型號的 price 。您將用 SOAP 請求格式對它作成文檔,但是首先讓我展示給您一般的 SOAP 請求和響應格式。


清單 14:SOAP 請求的一般格式


一條簡單的 SOAP 請求或響應只能表明一種服務的一個方法。包含一條 SOAP 請求的 Envelope 的一般格式遵從 清單 14。將這種一般格式與 清單 16 中的 getListOfModels() 的方法調用請求比較。在清單 16 中,我已經提供了方法和 URI 的名稱。既然在 getListOfModels() 中不需要參數,所以 <m:getListOfModels>清單 16中是一個空元素。


清單 15:一條 SOAP 響應的一般格式


清單 15 是一條一般的 SOAP 響應。Apache SOAP 服務器在方法名稱的後面增加了"Response"關鍵字並將返回值封入元素 <return> 中作爲一個直接子方法元素。若返回值是複合型結構,那麼 <return> 元素包含一個或多個 <item> 元素。將 清單 15清單 17 相比,清單 17 是來自 getListOfModels() 的實際響應。 清單 17包含一系列項目,作爲 Vector 數據類型,它是返回參數。 相似地, 清單 1819 展示了針對 MobilePhoneservice 的方法 getPrice() 的 SOAP 請求和響應。


清單 16:調用 getListOfModels() 方法的 SOAP 請求




清單 17:針對於來自清單 16 請求的 SOAP 響應



清單 18:對於 getPrice 方法的 SOAP 請求



清單 19:對於來自清單 18 請求的 SOAP 響應


 

在 SOAP 服務器上部署基於 WSDL 的服務

在此部分您將在 Apache SOAP 服務器上部署來自第 1 部分的 WSDL 服務。Apache SOAP 工具箱將 WSDL 服務信息保存在一個部署描述符文件裏面。部署描述符包含了 WSDL 服務的名稱和它擁有的所有方法。在運行時部署描述符會將這些名稱提供給 SOAP 服務器。同樣的部署描述符文件還包含了實現接口的 JavaBean 組件的地址。


清單 20:一個部署描述符的框架


清單 20是一個部署描述符的框架,爲了作爲基於 WSDL 服務的部署描述符使用,它需要三項信息( URN:SERVICE-URN、EXPOSED-METHODSIMPLEMENTING-CLASS)。 URN:SERVICE-URN 是被部署服務的名稱。在此例中它是 “urn:MobilePhoneservice”EXPOSED-METHODS 是一個單空格分隔的由服務提供的方法的列表。 在此部署中它是 getListOfModels getPrice

IMPLEMENTING-CLASS 是帶有全路徑的 Java 類名稱。例如, samples.phonequote.MobilePhoneservice 。 在此例中測試應用程序時,您有如下目錄結構:
Apache SOAP 服務器: C:/foo/SOAP-2_2
Mobile phone 服務實現:
C:/foo/SOAP-2_2/samples/phonequote/MobilePhoneservice

因此,IMPLEMENTING-CLASS 路徑請參照您安裝 SOAP 工具箱的目錄。 我沒有提供 Java 類的實際實現。 它取決於業務邏輯並且可以是任何東西。


清單 21:MobilePhoneservice 的部署描述符


清單 21是來自第 1 部分對 WSDL 文件的完整部署描述符。



 

SOAP 客戶機與 SOAP 服務器的通信

我已經提供過一個應用程序樣本來演示一臺 SOAP 客戶機與一臺 SOAP 服務器的通信。 爲此我給過三個列表:Startup.html( 清單 22)、Operation.html( 清單 23)和 Execute.jsp( 清單 24)。

StartUp.html( 清單 22)是一個簡單的 HTML 文件,提供給用戶一個 GUI 並詢問他將要調用哪一個 SOAP 方法。用戶會選擇一個他需要的方法。


清單 22:一個作爲前端的簡單 HTML 頁


Operation.html( 清單 23)將詢問客戶提供方法調用所需的參數。


清單 23:根據他或她所選擇的方法給予客戶一個 GUI


Execute.jsp( 清單 24)包含了所有的令人感興趣的代碼。它檢測所調用的方法和所傳遞的參數。然後發送給遠程服務器一個方法調用。


清單 24:檢測方法併發送給遠程服務器一個調用


爲了運行此應用程序,您需要兩臺 Apache SOAP 服務器。 一臺服務器將用來與用戶通信並託管 清單 222324。 另一臺服務器(也稱爲遠程服務器)就是我們需要部署第 1 部分所講的基於 WSDL 服務的地方(在前一節描述,“ 在 SOAP 服務器上基於 WSDL 服務的部署”)。 僅僅是爲了演示,遠程服務器的地址 http://localhost:8080/soap/servlet/rpcrouter 已經硬編碼在 Execute.jsp( 清單 24)中。在實際操作中您可以從 WSDL 文件中讀取它。

 


 

SOAP 中的簡單與複合數據類型

在此節中,我將從解釋簡單與複合數據類型的不同開始。然後展示如何在 SOAP 中對它們編碼。

簡單類型包括字符串、浮點數、整數、枚舉等。 例如一部手機的“name”的數據類型就是 “string” 。 複合類型由簡單類型組成但只代表一個實體。例如, “Student” 類型記錄可以有不同的屬性,如 “studentName” 屬於類型 “string”“studentRollNumber” 屬於類型 “int” 但都只代表一個實體 “Student”

清單 25 包含了一個名稱爲 “Mobile” 的複合數據類型。 您會在後面的 SOAP 請求中用到。


清單 25: “Mobile”類型的模式定義結構

清單 25 中的第 5 行展示了我們的類型名稱(Mobile),而第 6 行說明它是複合數據類型。因複合數據類型有屬性,所以在第 7 行到第 12 行展示了定義爲子元素的 “Mobile” 數據類型的屬性。

第 7 行聲明的元素展示了 “Mobile” 類型有一個名稱爲 “modelNumber” 的屬性且其類型爲 “int” (也就是說, “modelNumber” 只能採用整數值)。 類似的,第 9 行和第 10 行聲明的元素具有同樣的類型但有不同的屬性名稱。在第 8 行定義的元素具有名稱爲 “modelName” 的屬性且其類型是 “string”

第 11 行的元素因有位於第 12 行的、名稱爲 “simpleType” 的子元素,所以需要更好的理解。這裏您在複合類型 Mobile 中定義了一個簡單類型。simpleType 的名稱爲 “modelColor” 且它的類型是 “enumeration” 。它有一個屬性 “base” 具有的值爲 "xsd:string" ,這表明簡單類型 “modelColor” 具有在 SOAP 模式中定義的類型 “string” 的功能。在第 13 行到第 17 行中的每一個 <enumeration> 標記都具有一個屬性: “value”"white" "blue""black""red""pink" )。 枚舉類型使我們能夠從多項選項中選擇一個值。

 


 

在 SOAP 請求中使用複合數據類型

清單 26 演示了在 SOAP 請求中複合類型的使用。 它展示了一個在 Body 元素中的攜帶請求的 Envelope,在 Body 元素中,您正調用 “m” 名稱空間的 addModel 方法。 清單 26 使用數據類型 “Mobile” ,此數據類型在 清單 25中定義。

AddModel 方法攜帶一個類型爲 “Mobile” 的參數。我們以 “msd” 名稱空間引用來引用 “Mobile” 結構。請參閱清單 26 的 <SOAP-ENV:Envelope> 元素中的 "xmlns:msd" 聲明。 這是一個在 SOAP 請求中使用用戶定義數據類型的示例。


清單 26:實現在清單 25 中定義的“Mobile”結構



 

總結

在這一部分中,您已經學習了 SOAP 語法、請求、響應、HTTP 綁定和使用電子郵件的 SOAP 使用。您也瞭解了服務於 Apache SOAP 客戶機的 Apache SOAP 服務器。最後,我簡述了用戶定義數據類型的主題,它是一個需要我們仔細學習的高級主題。在此係列文章的下一部分,您會學習更多的用戶定義數據類型示例。我還會檢驗 SOAP 的互操作性(也就是說,怎樣使來自不同供應商的 SOAP 實現相互協調)。

 


 

參考資料

 


 

關於作者

Bilal Siddiqui 是一位 XML 顧問。自 1995 年畢業於 Lahore 工程技術大學電子工程專業後,他開始爲工業控制系統設計軟件解決方案。後來他轉到了 XML 並用自己 C++ 的編程經驗來構建基於 Web 和 WAP 的 XML 處理工具、服務器端的解析解決方案和服務應用程序。您可以通過 [email protected]發電子郵件給 Bilal 來索取本文中包含的代碼文件的拷貝。

  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章