引言
SOAP 消息有時需要與不同類型的附件一同傳輸,從法定文書的影印圖像到工程圖形,這些數據經常是二進制格式。例如,在因特網上傳輸的圖像絕大部分都是 GIF 或 JPEG 格式。本文描述一種標準的方法,將 SOAP 消息與一個或多個附件聯繫起來,並保留附件的原始格式,作爲一個多組分 MIME 結構來傳輸。這種方法結合了 Multipart/Related MIME 媒體類型的特殊用法和在 RFC2111、RFC2557 中所述的用 URI 引用 MIME 組分的方案,以次來實現 SOAP 消息與相關附件的共同傳輸。
這裏所描述的方法是將多組分 MIME 結構作爲傳輸協議綁定的一個基本組成部分,也就是說,對於 SOAP 消息而言,它等同於傳輸協議報頭。多組分結構,儘管這裏給出一個確定的名字―― SOAP 消息包,並不是一個可以明確標識的實體,因爲並沒有標記來明確地標識它是一個實體。在此有意避免增加新的、基於可辨識標記的實體類型。本文的目的在於表述怎樣利用現有的 SOAP 工具和標準 MIME 機制來承載和引用附件。換句話來講,我們用最簡單的方法證明了利用現有的技術已經可能實現什麼,而不用發明新的東西。對於消息包,更嚴格的語義需要新的實體類型。這種類型可通過擴展本文所述方法――創建一個新的 SOAP 頭條目來實現,比如可以爲消息包中的所有內容建立一個清單。
SOAP 消息包
一個 SOAP 消息包包含一個主體 SOAP1.1 消息,還可包含附加實體――詞法上不在 SOAP 消息內,卻與之相關。這些實體可以包含非 XML 格式的數據,消息包中的 SOAP1.1 消息可以引用這些附加的實體,這些附加的實體經常被非正式的稱爲附件。本部分描述怎樣構造 SOAP 消息包,及 SOAP 處理器該如何處理他們。
SOAP 消息包是通過 Multipart/Related(在 RFC 2387 中定義)媒體類型來構造的,構造規則如下:
主體 SOAP1.1 消息必需處於 Multipart/Related 結構的根部,因此,Multipart/Related 媒體報頭的 type 參數,將總是等於主體 SOAP1.1 消息的 Content-Type 頭的值,也就是 text/xml。
被引用的 MIME 組分,必須包含或者是一個 MIME 報頭 Content-ID(遵從 RFC 2045),或者是一個 MIME 報頭 Content-Location(遵從 RFC 2557)。
強烈建議在根部分包含一個 MIME 頭 Content-ID(遵從 RFC 2045),這樣就另需要在 Multipart/Related 媒體類型的參數中包含 start 參數。這樣能夠允許更健壯的錯誤檢測。
符合本規範的 SOAP 處理器,當接收到 SOAP1.1 消息(處於 Multipart/Related MIME 消息的根部)時,必須按照 SOAP1.1 規範中所定義的規定來處理 SOAP 消息。特別地,當 SOAP 處理器接到一條無效的消息時,必須產生如 SOAP1.1 中 4.4.1 節所述的客戶錯誤代碼。
使用 MIME Multipart/Related 對 SOAP 消息進行封裝,在語義上等同於一個 SOAP 協議綁定,SOAP 消息本身並不知道它是被封裝的。也就是說,在主體 SOAP 消息的內部沒有任何部分指出該 SOAP 消息是被封裝的。
下面的例子是帶一個附件的 SOAP1.1 消息,其中附件的內容是一幅關於已簽名索賠單的影印圖像(claim061400a.tiff)。
MIME-Version: 1.0 Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml; start="<[email protected]>" Content-Description: This is the optional message description. --MIME_boundary Content-Type: text/xml; charset=UTF-8 Content-Transfer-Encoding: 8bit Content-ID: <[email protected]> <?xml version='1.0' ?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> .. <theSignedForm href="cid:[email protected]"/> .. </SOAP-ENV:Body> </SOAP-ENV:Envelope> --MIME_boundary Content-Type: image/tiff Content-Transfer-Encoding: binary Content-ID: <[email protected]> ...binary TIFF image... --MIME_boundary--
SOAP 對附件的引用
主體 SOAP 消息中的 Header 條目和 Body 元素及其任一級子元素都可引用消息包中的其他實體。本節闡明一種方法,通過使用 SOAP 和 MIME 中現有的機制就可實現此功能。
根據 SOAP1.1 的數據編碼規則,一個 accessor 的值可以通過引用一個 href 屬性的值給出,就像一個資源可以通過 URI 來引用一樣。我們注意到 SOAP 編碼模式允許 href 屬性的值可以是任何的 URI,所以該屬性不僅可以用來引用 SOAP1.1 消息中的 XML 段,還可以引用其他任何資源。
這裏給出 SOAP1.1 中 href 屬性的一種使用方式,使屬性值是 SOAP 消息包中附件(作爲 MIME 的組分)的引用。主體 SOAP1.1 消息中 URI 引用的解析過程,基於 RFC2557 中的部分規定(關於具有 text/html 根文檔的多組分 MIME 消息)。我們採用這些關於 HTML 和描述上下文的規則,並將其應用於 SOAP1.1 消息上下文。另外,我們採用 RFC2396 中關於相對 URI 句法及其絕對化規則,而不是已經過時的、RFC2557 中使用的 RFC1808。
解析的過程分兩步進行:先將所有的 URI 轉化爲絕對 URI,然後解析絕對 URI。我們對這兩步進行規定。注意,這個處理過程不能應用於 RFC2396 中 4.2 節所定義的同文檔引用。SOAP1.1 的語義特徵包括通過使用一個帶段標識符的 href 屬性,來引用同一個 SOAP1.1 消息中的 XML 元素(基於一個保持不變的標籤,由 ID 屬性定義)。
在 RFC2396 中定義了將相對 URI 引用轉化爲絕對引用的過程,很具權威性。關於這個過程,我們需要詳細說明的是基礎 URI 的建立。RFC2396 中規定了建立基礎 URI 的過程框架,基於下列次序,按優先級排列。
基礎 URI 在文檔內:一種機制,明確規定在 SOAP1.1 消息內的基礎 URI 將是 XML 基礎的機制。
基礎 URI 來自封裝實體:在封裝了主體 SOAP1.1 消息的任何 MIME 實體中,有包含一個絕對 URI 的 Content-Location 報頭,那麼,最近的 Content-Location 報頭中的 URI 就是此實體的基礎 URI。
基礎 URI 來自回調 URI:爲 SOAP 消息包而回調的 URI,不允許被用作基礎 URI。
缺省基礎 URI:根據 RFC2557,如果不能從上面的方法中得到基礎 URI,本消息的基礎 URL 將是缺省基礎 URI。
構成 SOAP 消息包的 Multipart/Related 結構中,每個 MIME 組分至少有一個絕對 URI 標記,由三種情形:
如果給出的是一個 Content-Location 報頭並被賦予一個絕對 URI,那麼這個 URI 就是此組分的標記。
如果給出的是一個 Content-Location 報頭被賦予一個相對 URI,那麼就用上述規則的 2 和 4 來創建基礎 URI,並據此將相對 URI 轉化爲絕對 URI。所得的絕對 URI 便是此組分的標記。
如果給出的是一個 Content-ID 報頭,那麼此組分的絕對 URI 標記,將按照 RFC2111 中所規定的 CID URI 方案生成。
按如下方式對絕對 URI 進行解析。對於主體 SOAP1.1 消息中的每個 URI,將其按照上述方式轉化爲絕對 URI 後,與 Multipart/Related 結構中其他組分的絕對 URI 標記(由 Content-ID 和 Content-Location 報頭得出)進行比較,比較規則由 RFC2396 給出。如果發現一個匹配,相應 MIME 組分中所包含的實體就是被引用的資源。如果沒有匹配,就使用正常的、基於 URI 方案的解析規則。當 Content-ID 和 Content-Location 報頭的標記發生衝突時,用 RFC2557 中 8.3 節的規定加以解決,即使用 Content-ID 報頭值。
第 2 節的例子說明了在 SOAP 消息的 body 元素中使用 CID 的方法。顯然,該例中能夠使用遠程資源的引用。下面仍是這個例子,但使用了 Content-Location 報頭來標識實體,並用絕對 URI 來引用實體:
MIME-Version: 1.0 Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml; start="<http://claiming-it.com/claim061400a.xml>" Content-Description: This is the optional message description. --MIME_boundary Content-Type: text/xml; charset=UTF-8 Content-Transfer-Encoding: 8bit Content-ID: <http://claiming-it.com/claim061400a.xml> Content-Location: http://claiming-it.com/claim061400a.xml <?xml version='1.0' ?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> .. <theSignedForm href="http://claiming-it.com/claim061400a.tiff"/> .. </SOAP-ENV:Body> </SOAP-ENV:Envelope> --MIME_boundary Content-Type: image/tiff Content-Transfer-Encoding: binary Content-ID: <http://claiming-it.com/claim061400a.tiff> Content-Location: http://claiming-it.com/claim061400a.tiff ...binary TIFF image... --MIME_boundary ―
下面是同一個例子,這次使用了相對 URI,並使用 MIME Multipart/Related 結構基礎部分的 Content-Location 報頭的值最爲它們的基礎 URI:
MIME-Version: 1.0 Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml; start="<http://claiming-it.com/claim061400a.xml>" Content-Description: This is the optional message description. Content-Location: http://claiming-it.com/ --MIME_boundary Content-Type: text/xml; charset=UTF-8 Content-Transfer-Encoding: 8bit Content-ID: <http://claiming-it.com/claim061400a.xml> Content-Location: claim061400a.xml <?xml version='1.0' ?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> .. <theSignedForm href="claim061400a.tiff"/> .. </SOAP-ENV:Body> </SOAP-ENV:Envelope> --MIME_boundary Content-Type: image/tiff Content-Transfer-Encoding: binary Content-Location: claim061400a.tiff ...binary TIFF image... --MIME_boundary--
最後這個例子使用了相對 URI,但並沒有明確聲明基礎 URI,這樣就會用到規則 4 來建立一個基礎 URI。此時,SOAP 消息中的相對 URI 和 Content-Location 標記都要用到此基礎 URI:
MIME-Version: 1.0 Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml; start="<[email protected]/s445>" Content-Description: This is the optional message description. --MIME_boundary Content-Type: text/xml; charset=UTF-8 Content-Transfer-Encoding: 8bit Content-ID: <[email protected]/s445> Content-Location: claim061400a.xml <?xml version='1.0' ?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> .. <theSignedForm href="the_signed_form.tiff"/> .. </SOAP-ENV:Body> </SOAP-ENV:Envelope> --MIME_boundary Content-Type: image/tiff Content-Transfer-Encoding: binary Content-ID: <[email protected]/s445> Content-Location: the_signed_form.tiff ...binary TIFF image... --MIME_boundary-
值得注意的是,在 SOAP 消息中,作爲 href 屬性的值而出現的 URI 引用,並未暗示接收 SOAP 處理器必需解析該 URI。SOAP 處理器可以根據消息的處理語義來決定是否需要解析 URI。接收 SOAP 處理器可以選擇忽略該 URI,儘管它是用來引用一個 MIME 附件。相反地,消息包所有的附件也可能均不被 SOAP 消息所引用。
與 SOAP1.1 的關係
帶附件的 SOAP 消息包是對 SOAP1.1 所定義的傳輸綁定機制的一個擴展。將 SOAP1.1 消息作爲 Multipart/Related MIME 結構的根組分,與其他內容一同打包,可以看作是通過任何能夠傳輸 MIME 內容的通信協議,承載 SOAP1.1 消息的一種特殊方法。SOAP 處理器要同時支持 MIME 編碼格式和底層通信協議,並且在處理 SOAP1.1 消息時,必須遵循 SOAP1.1 中所有關於消息及底層傳輸綁定的規定。
HTTP 綁定
因爲是基於 SOAP1.1 的,所以這裏並不描述異步消息、或同步請求 / 響應交互模式。這裏所講的 HTTP 綁定只涉及到在構建 SOAP 消息包時,HTTP 報頭與 MIME 報頭之間的關係,而對於交互模式絲毫沒有涉及。
在 HTTP 消息中承載多組分 MIME 結構的基本方法是:限定用 MIME 編碼的內容於 MIME 組分內,並在 HTTP 本身報頭中使用 Multipart/Related 媒體類型。在 HTTP 消息中包含 SOAP 消息包的規則如下:
MIME 報頭 Content-Type:Multipart/Related 必須作爲一個 HTTP 報頭出現,在第 2 節中所規定的關於此報頭中參數的規定在這裏也適用。
在 MIME 規範中定義的其他含義報頭(如 Content-Transfer-Encoding)不能作爲 HTTP 報頭出現。特別是“MIME-Version: 1.0”報頭,絕對不能作爲 HTTP 報頭出現。注意,在 HTTP1.1 中定義了許多與 MIME 類似的報頭,有具體的含義。這些報頭當然可以自由出現。
包含了 SOAP 消息和附件的各 MIME 組分,構成了 HTTP 消息體,並且按第 2 節中所述的方式表示,包括恰當的 MIME 報頭。
下面的例子是一則 HTTP 消息,包含一個 SOAP 消息包,包內含有兩個附件構成一則汽車保險索賠。SOAP1.1 消息內包含索賠數據,與一個已簽署索賠單的影印圖像(claim.tiff)和一幅被毀壞汽車的數字照片(car.jpeg)一同發送。
POST /insuranceClaims HTTP/1.1 Host: www.risky-stuff.com Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml; start="<[email protected]>" Content-Length: XXXX SOAPAction: http://schemas.risky-stuff.com/Auto-Claim Content-Description: This is the optional message description. --MIME_boundary Content-Type: text/xml; charset=UTF-8 Content-Transfer-Encoding: 8bit Content-ID: <[email protected]> <?xml version='1.0' ?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <claim:insurance_claim_auto id="insurance_claim_document_id" xmlns:claim="http://schemas.risky-stuff.com/Auto-Claim"> <theSignedForm href="cid:[email protected]"/> <theCrashPhoto href="cid:[email protected]"/> <!-- ... more claim details go here... --> </claim:insurance_claim_auto> </SOAP-ENV:Body> </SOAP-ENV:Envelope> --MIME_boundary Content-Type: image/tiff Content-Transfer-Encoding: base64 Content-ID: <[email protected]> ...Base64 encoded TIFF image... --MIME_boundary Content-Type: image/jpeg Content-Transfer-Encoding: binary Content-ID: <[email protected]> ...Raw JPEG image.. --MIME_boundary--
結束語
通過利用 SOAP 和 MIME 自身的功能,就能實現 SOAP 消息與相關實體的綁定,達到一同傳輸的目的。本文詳細介紹了消息格式、對附件的引用方法以及相應 SOAP 處理器的處理規則,最後給出了 SOAP 消息包通過 HTTP 協議傳時的具體消息格式。本文所介紹的 SOAP 消息與附件的綁定方法,適用於各種格式的附件,必將對 B2B 消息互換產生巨大的促進作用。
參考文獻
[SOAPATTACH] SOAP Messages with Attachments( http://www.w3.org/TR/2000/NOTE-SOAP-attachments-20001211)
[SOAP] Simple Object Access Protocol (SOAP) Version 1.1 (http://www.w3.org/TR/SOAP/)
[XML] Extensible Markup Language (XML) 1.0 (http://www.w3.org/TR/1998/REC-xml-19980210)
[MultipartRelated] The MIME Multipart/Related Content-type (http://www.ietf.org/rfc/rfc2387.txt)
[CID] Content-ID and Message-ID Uniform Resource Locators http://www.ietf.org/rfc/rfc2111.txt
[URI] Uniform Resource Identifiers (URI): Generic Syntax (http://www.ietf.org/rfc/rfc2396.txt)
[XMLBASE] XML Base http://www.w3.org/TR/xmlbase
[HTTP] Hypertext Transfer Protocol -- HTTP/1.1 (http://www.ietf.org/rfc/rfc2616.txt)
[SMTP] Simple Mail Transfer Protocol (http://www.ietf.org/rfc/rfc0821.txt)