DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> 向 Web 服務傳遞文件
向 Web 服務傳遞文件
編輯:XML詳解     

Web 服務協議已經從支持帶有簡單參數的非常簡單的請求,發展到對現代的面向對象語言的完整支持。XML-RPC 看來是 Web 服務的早期形式之一,僅僅支持簡單類型 —— 字符串、整數、布爾值等等。SOAP 向前邁出了一步,有了用於對象的編碼規則。最近的發展 —— 在二進制數據方面的改進 —— 來自 帶附件的 SOAP。

  帶附件的 SOAP 最初是作為 SOAP 1.1 的擴展提出的,得到了主流 SOAP 工具箱的支持。盡管 W3C 正式發布的 SOAP 1.2 還不支持附件,但是正努力實現在不遠的將來(理想情況下)把它包含進來。

  Web 服務與二進制數據

  我毫不懷疑 XML 在應用程序集成中取得的成功,源自於對文本性編碼的依賴(與二進制協議相對而言,如 CORBA —— 一種面向對象的 RPC 協議,RMI —— Java 專用的 RPC 標准)。優先選擇文本性編碼有幾種原因,但最重要的可能是因為它容易調試,而且如果必要的話容易完成專門的實現。

  對文本性編碼的依賴仍然有不利的一面,XML 對引入二進制數據沒有提供有效的解決方案。按照 W3C XML Schema 規范,二進制數據應該采用 base 64 或者十六進制編碼。不幸的是,base 64 編碼的數據比未編碼的數據大 50%,而十六進制編碼的數據是原來數據的兩倍長。對於小段的二進制數據這種代價還可以接受,但對於較大的數據集顯然是個問題。

  二進制數據在許多應用程序中都很有用。比如:

  安全應用程序需要密碼、散列、證書以及加密數據本身。

  多媒體應用程序處理圖片、音樂和視頻。

  在一些應用程序中,數據的 XML 表示被認為效率太低,比如 CAD/CAM。


 XML 之前的成千上萬種文件格式:字處理、電子表格、字體、向量圖形、系譜等等。

  盡管為這些文件格式創建 XML 版本是可能的(如用於向量圖形的 SVG),但二進制數據已經存在了很長時間並且可能仍然非常普及。

  最後還有 XML 自身的問題。在一個 XML 文檔中包括另一個 XML 文檔不是很簡單的事(語法正確的解決方法依賴於 CDATA 節和字符轉義)。

  MIME 與 base 64

  這裡澄清一種常見的混淆,MIME 並沒有強制要求 base 64 編碼。具體而言,HTTP 實現沒有對附件編碼,只有郵件客戶編碼附件以突破 SMTP 的局限性(因此與 XML 沒有比較的價值)。

  為了解決這些應用程序的需要,Web 服務必須有效地支持二進制數據。提出的解決方案是帶有附件的 SOAP,該協議的核心是從 XML 有效負載中去掉二進制信息將其直接作為 multipart/related MIME 內容放在 HTTP 請求中。

  在設計使用二進制數據的 Web 服務時,可以選的方法有:

  如果數據集很小,可以考慮在 XML 載荷中使用 base 64 編碼,對於小的數據集這樣做的代價不構成問題。

  如果數據集很大,使用附件是唯一可行的選擇。

  清單 1 是一個帶有 base 64 編碼參數的 SOAP 請求。注意其中的 address 元素。

清單 1. base 64 編碼的參數

POST /ws/retrIEve HTTP/1.0 
Content-Type: text/XML; charset=utf-8 
Accept: application/soap+XML multipart/related, text/* 
Host: localhost:8080 
SOAPAction: "" 
Content-Length: 540 
<?XML version="1.0" encoding="UTF-8"?> 
<soapenv:Envelope xmlns:soapenv="http://schemas.XMLsoap.org/soap/envelope/" 
         xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
 <soapenv:Body> 
 <ps:retrIEve 
      soapenv:encodingStyle="http://schemas.XMLsoap.org/soap/encoding/" 
      XMLns:ps="http://psol.com/2004/ws/retrIEve"> 
  <address xsi:type="xsd:base64Binary">d3d3Lm1hcmNoYWwuY29t</address> 
 </ps:retrIEve> 
 </soapenv:Body> 
</soapenv:Envelope>

實現附件

  Java 開發人員可以通過 JAX-RPC(基於 XML 的 RPC 的 Java API)和 SAAJ(用於 Java 的帶附件 SOAP API)使用附件。不要讓縮寫詞 SAAJ 欺騙了您:JAX-RPC 支持附件。JAX-RPC 和 SAAJ 的區別在於抽象的層次而不是功能。

  JAX-RPC 是一種高層次的 API,比 SAAJ 更抽象。它在 RMI 層背後隱藏了大部分面向 SOAP 協議的問題。開發人員處理的是 Java 對象,預處理程序將其轉成 SOAP 節點。JAX-RPC 使用 java.awt.Image 和 Javax.activation.DataHandler 類表示附件。

  SAAJ 更接近於協議。使用 SAAJ 創建 SOAP 消息和 JAX-RPC 相比要做更多的工作(而且沒有提供到 WSDL 的自動鏈接),因此多數情況您可能更願意使用 JAX-RPC。但是為了說明附件到底是如何工作的,由於它的底層特性 SAAJ 更加合適。清單 2 是一個帶有附件的 SOAP 請求。該請求要求服務器改變一個圖片的大小,因為圖片很大,使用附件更有效。

清單 2. 附件參數

POST /ws/resize HTTP/1.0 
Content-Type: multipart/related; type="text/XML"; 
   start="<EB6FC7EDE9EF4E510F641C481A9FF1F3>"; 
   boundary="----=_Part_0_7145370.1075485514903" 
Accept: application/soap+XML, multipart/related, text/* 
Host: localhost:8080 
SOAPAction: "" 
Content-Length: 1506005 
------=_Part_0_7145370.1075485514903 
Content-Type: text/XML; charset=UTF-8 
Content-Transfer-Encoding: binary 
Content-Id: <EB6FC7EDE9EF4E510F641C481A9FF1F3> 
<?XML version="1.0" encoding="UTF-8"?> 
<soapenv:Envelope xmlns:soapenv="http://schemas.XMLsoap.org/soap/envelope/" 
         xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
 <soapenv:Body> 
 <ps:resize 
     soapenv:encodingStyle="http://schemas.XMLsoap.org/soap/encoding/" 
     XMLns:ps="http://psol.com/2004/ws/resize" 
     xmlns:SOAP-ENC="http://schemas.XMLsoap.org/soap/encoding/"> 
  <source href="cid:E1A97E9D40359F85CA19D1B8A7C52AA3"/> 
  <percent>20</percent> 
 </ps:resize> 
 </soapenv:Body> 
</soapenv:Envelope> 
------=_Part_0_7145370.1075485514903 
Content-Type: image/jpeg 
Content-Transfer-Encoding: binary 
Content-Id: <E1A97E9D40359F85CA19D1B8A7C52AA3> 
note: binary data deleted... 
------=_Part_0_7145370.1075485514903--

清單 3 示范了該 SOAP 請求的創建。該請求要求服務器改變圖像的大小。過程如下:

  通過工廠創建 SOAP 連接和 SOAP 消息對象。

  從消息對象中檢索消息體(中間步驟:檢索 SOAP 部分和信封)。

  創建一個新的 XML 元素表示請求並設置編碼方式。

  創建附件並使用 DataHandler 對象初始化。

  創建另外的元素表示兩個參數( source 和 percent )。

  通過添加 href 屬性把附件與第一個元素關聯。附件通過 cid (content-id)URL 引用。

  直接把第二個參數的值設成文本並調用服務。

  服務使用改變了大小的圖像(同樣作為附件)作為應答。檢索返回的圖像之前可以測試 SOAP 錯誤碼(表示一個錯誤)。如果沒有錯誤,則作為文件檢索附件並處理。

清單 3. 使用 SAAJ

public File resize(String endPoint,File file) 
{ 
  SOAPConnection connection = 
   SOAPConnectionFactory.newInstance().createConnection(); 
  SOAPMessage message = MessageFactory.newInstance().createMessage(); 
  SOAPPart part = message.getSOAPPart(); 
  SOAPEnvelope envelope = part.getEnvelope(); 
  SOAPBody body = envelope.getBody(); 
  SOAPBodyElement Operation = 
   body.addBodyElement( 
     envelope.createName("resize", 
               "ps", 
               "http://psol.com/2004/ws/resize")); 
  Operation.setEncodingStyle("http://schemas.XMLsoap.org/soap/encoding/"); 
  DataHandler dh = new DataHandler(new FileDataSource(file)); 
  AttachmentPart attachment = message.createAttachmentPart(dh); 
  SOAPElement source = Operation.addChildElement("source",""), 
        percent = Operation.addChildElement("percent",""); 
  message.addAttachmentPart(attachment); 
  source.addAttribute(envelope.createName("href"), 
            "cid:" + attachment.getContentId()); 
  width.addTextNode("20"); 
  SOAPMessage result = connection.call(message,endPoint); 
  part = result.getSOAPPart(); 
  envelope = part.getEnvelope(); 
  body = envelope.getBody(); 
  if(!body.hasFault()) 
  { 
   Iterator iterator = result.getAttachments(); 
   if(iterator.hasNext()) 
   { 
     dh = ((AttachmentPart)iterator.next()).getDataHandler(); 
     String fname = dh.getName(); 
     if(null != fname) 
      return new File(fname); 
   } 
  } 
  return null; 
}

  注意, 清單 3清楚地表明附件是在 XML 消息的 外部!為了提高效率這是必需的。

  談到效率,看一看清單 4,這是 清單 3 更常見的 JAX-RPC 版本(也短得多)。JAX-RPC 預處理程序生成一個存根程序,極大簡化了編碼。您把 DataHandler 對象作為參數傳遞,JAX-RPC 自動生成附件。

清單 4. 更有效的 JAX-RPC

public File resize(File file) 
  throws ServiceException, RemoteException 
{ 
  AttachmentService service = new AttachmentServiceLocator(); 
  AttachmentTip port = service.getAttachmentTip();  // get stub 
  DataHandler dh = new DataHandler(new FileDataSource(file)); 
  DataHandler result = port.resize(dh,20); 
  return new File(result.getName()); 
} 

  結束語

  選擇是一件好事,而 SOAP 為您處理二進制數據提供了選擇:您可以在 XML 有效負載中使用 base 64 編碼——對於小的數據集這種方法很好,也可以向請求中附加大的沒有編碼的二進制文件。



XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved