掌握 Ajax,第 7 部分: 在請求和響應中使用 XML

來源:互聯網
上載者:User

瞭解什麼時候適合什麼時候不適合使用 XML

文檔選項

列印本頁

列印本頁

層級: 中級

Brett McLaughlin (brett@oreilly.com), 作家,編輯, O'Reilly and Associates

2006 年 10 月 23 日

偶爾使用 Ajax 的開發人員也會注意到 Ajax 中的 x 並意識到它代表 XML。XML 是編程中最常用的資料格式之一,對於非同步應用程式中的伺服器響應能夠帶來切實的好處。在本文中,您將看到伺服器如何在請求響應中發送 XML。

現在如果不使用 XML 就不能進行任何有意義的編程。無論考慮轉向 XHTML 的網頁設計人員、使用 JavaScript 的 Web 程式員、使用部署描述檔案和資料繫結的伺服器端程式員,還是研究基於 XML 的資料庫的後端開發人員,都在使用這種可延伸標記語言 (XML)。因此,XML 被認為是 Ajax 底層的核心技術之一就不足為奇了。

但是,這種觀點反映到 Ajax 應用程式就表現在其核心對象所選的名稱 —— XMLHttpRequest,這個名稱不是很好,因為它並沒有反映技術上的實際情況。換句話說,多數人之所以認為 XML 是 Ajax 的核心組成部分,僅僅是因為他們想當然地以為 XMLHttpRequest 對象在任何時候都使用 XML。但實情並非如此,本文第一部分給出了原因。實際上,您將看到在多數 Ajax 應用程式中 XML 很少出現。

XML 確實有應用在 Ajax 中,而且 XMLHttpRequest 也支援這種用法。也確實沒有什麼能阻擋您向伺服器發送 XML。在本系列前面的文章中,我們使用普通文本和名/值參數發送資料,但 XML 也是一種可行的格式。本文將介紹如何來這樣做。但最重要的是,我將討論為何可以使用 XML 作為請求格式,以及為何在多數情況下不應該使用它。

XML:到底用沒用?

對 Ajax 應用程式及它們使用 XML 的情況很容易犯想當然的錯誤:這種技術的名稱(Ajax)及其使用的核心對象(XMLHttpRequest)都暗示了 XML 的使用,談到 Ajax 應用程式的時候也經常聽到 XML。但是,這種觀點大錯特錯,如果希望在編寫非同步應用程式時真正做到胸有成竹,必須知道這種想法是錯誤的,而且最好知道為什麼錯誤。

XMLHttpRequest:糟糕的名稱和 HTTP

一項技術可能遇到的最糟的境況之一是它變得太炙手可熱以至於無法再改變它的一些基本內容。XMLHttpRequest 恰恰是這種情形,它是 Ajax 應用程式中使用的基本對象。聽起來它似乎是為通過 HTTP 要求發送 XML 或者以某種 XML 格式發出 HTTP 要求而設計的。但不論這個對象的名稱聽起來像什麼,實際上它要的只不過是為客戶機代碼(在網頁中通常是 JavaScript)提供一種發送 HTTP 要求的方式。僅此而已,別無其他。

因此,如果將 XMLHttpRequest 改成某種更準確的名稱可能更好一些,比如 HttpRequest,或者簡簡單單的 Request。但是,現在成千上萬的人在應用程式中使用了 Ajax,而且我們知道需要幾年時間(如果不是十幾年的話)大部分使用者才會改用 Internet Explorer 7.0 或 Firefox 1.5 這些新版本的瀏覽器,因此這麼修改實際上是不可行的。最終我們不得不使用 XMLHttpRequest,這就要求開發人員要知道其名不符實的這一事實。

在一定程度上講,對於不支援 XMLHttpRequest 的瀏覽器(特別是在 Windows 上)的最佳回溯方法之一就是使用 Microsoft IFRAME 對象。聽起來可不像是 XML、HTTP 或請求,是不是?當然,所有這些都可能涉及到,但是這正清楚地說明了一點 —— XMLHttpRequest 對象更多的是關於在不重新載入頁面的情況發出請求,而不會太多地涉及 XML 甚至 HTTP。

請求是 HTTP 而非 XML

另一種常見的錯誤是認為 XML 在幕後使用 —— 坦白地說,我也曾這麼認為!但是,持這種觀點表明您對這種技術還不甚瞭解。當使用者開啟瀏覽器從伺服器上請求網頁時,會輸入 http://www.google.com 或者 http://www.headfirstlabs.com 這樣的東西。即便不輸入 http://,瀏覽器也會在地址欄的這部分加上。第一部分,即 http://,是關於如何通訊的很直觀的線索:通過超文字傳輸通訊協定 (HTTP) HTTP。在網頁中編寫代碼與伺服器通訊時,無論使用 Ajax 還是普通的表單 POST,甚至超連結,打交道的都是 HTTP。

HTTPS:仍然是 HTTP

那些剛接觸 Web 的人可能對 https://intranet.nextel.com 這樣的 URL 感到奇怪。https 表示安全的 HTTP,只是使用了比一般 Web 請求更安全的 HTTP 協議形式。因此即便是 HTTPS,實際上用的仍然是 HTTP,雖然增加了某些安全層來擋住那些好奇的眼睛。

既然瀏覽器和伺服器之間的所有 Web 通訊都通過 HTTP 進行,認為 XML 是 XMLHttpRequest 幕後所用的某種傳輸技術的想法就毫無道理了。當然在 HTTP 要求可以發送 XML,但是 HTTP 是一個精確定義的協議,短時間內不可能消失。除了在請求中明確使用 XML,或者伺服器用 XML 發送響應之外,XMLHttpRequest 對象使用的只是普普通通的 HTTP。因此,當再有人對您說 “哦,稱為 XMLHttpRequest 是因為在幕後使用 XML” 的時候,您最好一笑了之,並耐心地解釋什麼是 HTTP,告訴他們雖然 XML 可以通過 HTTP 發送,但 XML 是一種資料格式而不是傳輸協議。通過這樣的討論,加深對它的理解。



回頁首

使用 XML(真正)

到目前為止,我說的只是 Ajax 在哪些地方使用 XML。但 Ajax 中的 xXMLHttpRequest 中的 XML 仍然有其實際意義,在 Web 應用程式中使用 XML 有多種選擇。這一節將討論基本的選擇,剩下的部分再深入探討細節問題。

XML 選項

在非同步應用程式中 XML 有兩種基本的用法:

  • 以 XML 格式從網頁向伺服器發送請求
  • 以 XML 格式在網頁中從伺服器接收請求

其中第一種用法,即用 XML 發送請求,需要將請求的格式設定為 XML,可以使用 API 來完成,也可以與文本連成字串,然後將結果發送到伺服器。按照這種思路,主要的任務就是通過既符合 XML 規則又能被伺服器理解的方式構造請求。因此這裡的關鍵實際上是 XML 格式,得到需要發送的資料之後,只需要用 XML 文法將其封裝起來。本文後面討論 XML 在 Ajax 應用程式中的這種用法。

第二種用法,即用 XML 接收請求,需要從伺服器上接收響應,然後從 XML 提取資料(同樣,可以用 API 或者採用蠻力方法)。這種情況下,關鍵在於來自伺服器的資料,而您恰好需要從 XML 中提取這些資料以便使用。這是本系列下一期文章的主題,到那時候我們再詳加討論。

一點忠告

再詳細討論使用 XML 的細節之前,首先給您一句忠告:XML 不是一種簡潔、快速和節省空間的格式。在後面幾節以及本系列的下一期文章中將看到,在上下文中使用 XML 確實有一些很好的理由,XML 與普通文本的請求和響應(特別是響應)相比也確實有一些長處。但是,和普通文本相比,XML 通常總會佔用更多的空間,速度也更慢,因為需要在訊息中增加 XML 所需要的標籤和語義。

如果需要編寫速度很快、看起來像案頭應用的程式,XML 可能不是最佳選擇。如果從普通文本開始,然後發現確實需要 XML,那麼就使用它;但是如果從一開始就使用 XML,基本上可以肯定一定會降低應用程式的響應性。多數情況下,與將文本轉化成下面這種 XML 相比,發送普通文本會更快一些(使用類似 name=jennifer 的名/值對):

<name>jennifer</name>

看看哪些地方使 XML 增加了處理時間:將文本封裝成 XML;發送額外資訊(要注意我沒有包含任何包圍元素、XML 頭或者可能出現在實際請求中的其他任何內容);讓伺服器解析 XML、產生響應、用 XML 封裝響應,並將它發送網頁;讓網頁解析響應,最後使用它。因此要清楚什麼時候使用 XML,不要一開始就認為它在很多情況下都能夠加快應用程式;但,它可以增強靈活性,這就是我們現在要討論的。



回頁首

從客戶機到伺服器的 XML

我們來看看將 XML 作為從客戶機向伺服器發送資料的格式。我們首先討論技術上的實現,然後花些時間分析什麼時候適合什麼時候不適合使用它。

發送名/值對

在您編寫的 90% Web 應用程式中,最終都會使用名/值對發送到伺服器。比方說,如果使用者在網頁表單中輸入姓名和地址,可能希望資料採用下列形式:

firstName=LarrylastName=Gullahornstreet=9018 Heatherhorn Drivecity=Rowlettstate=TexaszipCode=75080

如果使用普通文本把這些資料發送到伺服器,可以使用清單 1 所示的代碼。類似於本系列第一期文章中使用的那個例子。請參閱參考資料

清單 1. 使用普通文本發送名/值對

function callServer() {  // Get the city and state from the Web form  var firstName = document.getElementById("firstName").value;  var lastName = document.getElementById("lastName").value;  var street = document.getElementById("street").value;  var city = document.getElementById("city").value;  var state = document.getElementById("state").value;  var zipCode = document.getElementById("zipCode").value;  // Build the URL to connect to  var url = "/scripts/saveAddress.php?firstName=" + escape(firstName) +    "&lastName=" + escape(lastName) + "&street=" + escape(street) +    "&city=" + escape(city) + "&state=" + escape(state) +    "&zipCode=" + escape(zipCode);  // Open a connection to the server  xmlHttp.open("GET", url, true);  // Set up a function for the server to run when it's done  xmlHttp.onreadystatechange = confirmUpdate;  // Send the request  xmlHttp.send(null);}

將名/值對轉化成 XML

如果希望這樣使用 XML 作為資料格式,首先要做的是找到一種基本 XML 格式來儲存資料。顯然,名/值對可以全部轉化成 XML 元素,以其中的名稱作為元素名,值作為元素的內容:

<firstName>Larry</firstName><lastName>Gullahorn</lastName><street>9018 Heatherhorn Drive</street><city>Rowlett</city><state>Texas</state><zipCode>75080</zipCode>

當然,XML 要求有一個根項目;如果使用文檔片段(XML 文檔的一部分)的話則需要一個封閉元素。因此可能需要將上述 XML 轉化成下面的形式:

<address>  <firstName>Larry</firstName>  <lastName>Gullahorn</lastName>  <street>9018 Heatherhorn Drive</street>  <city>Rowlett</city>  <state>Texas</state>  <zipCode>75080</zipCode></address>

現在基本上可以準備在 Web 客戶機上建立這種結構並發送到伺服器了。

通訊,口頭上的

在網路上傳輸 XML 之前,需要保證伺服器以及發送資料的指令碼能夠接受 XML。現在對很多人來說這麼強調似乎有點多餘,認為這是理所當然的,但是很多新手往往認為只要通過網路發送 XML,就能夠被正確地接收和解釋。

實際上,需要兩個步驟來保證發送的 XML 的資料能夠被正確地接收:

  1. 保證向其發送 XML 的指令碼能夠接受 XML 資料格式。
  2. 保證指令碼認可發送資料所採用的特定 XML 格式和結構。

這兩方面都可能要求您進行人際溝通,必須明確地告知對方!嚴格地說,如果確實需要發送 XML 資料,多數指令碼作者都會協助您,因此尋找能夠接受 XML 的指令碼應該不難。但是,仍然需要保證格式是指令碼所希望的格式。比方說,假設伺服器接受下列格式的資料:

<profile>  <firstName>Larry</firstName>  <lastName>Gullahorn</lastName>  <street>9018 Heatherhorn Drive</street>  <city>Rowlett</city>  <state>Texas</state>  <zip-code>75080</zip-code></profile>

看起來和上面的 XML 類似,只有兩點不同:

  1. 來自客戶機的 XML 封裝在 address 元素,但是伺服器要求資料封裝在 profile 元素中。
  2. 來自客戶機的 XML 使用了 zipCode 元素,而伺服器希望郵遞區號放在 zip-code 元素中。

從大的層面上來說,這些小問題僅僅是伺服器接收和處理資料的區別,但是伺服器會徹底失敗,在網頁上(可能向其使用者)顯示意義含糊的錯誤訊息。因此必須明確伺服器的期望的格式,並把要發送的資料塞進那種格式。然後,只有在這時才會涉及到從客戶機向伺服器發送 XML 資料的真正的技術問題。

向伺服器發送 XML

當向伺服器發送 XML 的時候,更多的代碼用於擷取資料和封裝成 XML,而不是真正的傳輸資料。實際上,只要準備好發送到伺服器的 XML 字串,發送工作就和普通文本一樣了,如清單 2 所示。

清單 2. 用 XML 發送名/值對

function callServer() {  // Get the city and state from the Web form  var firstName = document.getElementById("firstName").value;  var lastName = document.getElementById("lastName").value;  var street = document.getElementById("street").value;  var city = document.getElementById("city").value;  var state = document.getElementById("state").value;  var zipCode = document.getElementById("zipCode").value;  var xmlString = "<profile>" +    "  <firstName>" + escape(firstName) + "</firstName>" +    "  <lastName>" + escape(lastName) + "</lastName>" +    "  <street>" + escape(street) + "</street>" +    "  <city>" + escape(city) + "</city>" +    "  <state>" + escape(state) + "</state>" +    "  <zip-code>" + escape(zipCode) + "</zip-code>" +    "</profile>";  // Build the URL to connect to  var url = "/scripts/saveAddress.php";  // Open a connection to the server  xmlHttp.open("POST", url, true);  // Tell the server you're sending it XML  xmlHttp.setRequestHeader("Content-Type", "text/xml");  // Set up a function for the server to run when it's done  xmlHttp.onreadystatechange = confirmUpdate;  // Send the request  xmlHttp.send(xmlString);}

大部分代碼都很簡單,只有少數地方值得提一下。首先,請求中的資料必須手工格式化為 XML。閱讀了三篇關於使用文檔物件類型的文章之後,再來討論它是不是很簡單了?雖然不禁止在 JavaScript 中使用 DOM 建立 XML 文檔,但是在通過 GET 或 POST 請求發送到網路上之前必須將 DOM 對象轉化成文本。因此使用常規字串操作來格式化資料更簡單一些。當然,這樣很容易出現錯誤和誤輸入,因此在編寫處理 XML 的代碼時必須非常小心。

建立 XML 之後,按照和發送文本基本相同的方式開啟串連。對於 XML 最好使用 POST 請求,因為有些瀏覽器限制了 GET 請求字串的長度,而 XML 可能很長,可以看到清單 2 中把 GET 改成了 POST 方法。此外,XML 通過 send() 方法發送,而不是附加在請求 URL 最後的參數。這些都是非常細微的區別,很容易修改。

但是必須編寫一行新的代碼:

xmlHttp.setRequestHeader("Content-Type", "text/xml");

看起來很難理解,它只不過是告訴伺服器要發送的是 XML 而不是一般的名/值對。無論哪種情況,發送的資料都是文本,但這裡使用 text/xml 或者 XML 作為普通文本發送。如果使用名/值對,對應的行應該是:

xmlHttp.setRequestHeader("Content-Type", "text/plain");

如果忘記告訴伺服器發送的是 XML,就會出現問題,因此不要忘掉這一步驟。

完成這些之後,剩下的就是調用 send() 並傳入 XML 字串了。伺服器將收到您的 XML 請求,並(假設已經做好了準備工作)接受 XML,解釋它,然後返迴響應。實際上要做的只有這麼多 —— XML 請求只需要稍微修改代碼。



回頁首

發送 XML:好還是不好?

在結束 XML 響應的 XML 請求(以及本文)之前,我們花點時間討論一下在請求中使用 XML 的感受。前面已經提到,就傳輸而言 XML 完全不是最快的方式,但是還有更多因素要考慮。

構造 XML 不是簡單的事情

首先必須認識到,對於請求來說構造 XML 不是簡單的事。如清單 2 所示,資料很快就會和 XML 語義糾纏在一起:

var xmlString = "<profile>" +  "  <firstName>" + escape(firstName) + "</firstName>" +  "  <lastName>" + escape(lastName) + "</lastName>" +  "  <street>" + escape(street) + "</street>" +  "  <city>" + escape(city) + "</city>" +  "  <state>" + escape(state) + "</state>" +  "  <zip-code>" + escape(zipCode) + "</zip-code>" +  "</profile>";

似乎還不壞,但是要知道這是只有六個欄位的 XML 片段。開發的多數 Web 表單都有十到十五個欄位,雖然不一定所有的請求都使用 Ajax,但是應該考慮這種情況。至少要花和實際資料同樣多的時間來處理角括弧和標籤名稱,有可能使本來很少的輸入變得非常大。

這裡的另一個問題前面已經提到,即必須手工建立 XML。使用 DOM 不是一種好的選擇,因為沒有簡單易行的辦法將 DOM 對象轉化成在請求中發送的字串。因此像這樣使用字串處理是最好的辦法,不過也是一種維護起來最困難和新開發人員最難理解的方法。在這個例子中,所有 XML 都在一行中構造完成,如果分為多步只會更加混亂。

XML 沒有為請求增加任何東西

除了複雜性的問題之外,和普通文本以及名/值對相比,在請求中使用 XML 實際上沒有多少好處(如果有的話)。要注意,本文堅持使用前面用名/值對發送的同一些資料(請參閱清單 1)來用 XML 發送。我沒有提什麼資料能用 XML 但是不能用普通文本發送,這是因為實際上沒有任何東西可用 XML 而不能用普通文本發送。

事實上這就是 XML 和請求的底線:不是一定非要這麼做不可。在本系列的下一期文章中將看到伺服器可以使用 XML 實現普通文本很難做到的一些事情,但請求不屬於這種情況。因此除非和接受 XML 的指令碼(確實存在這樣的指令碼)打交道,在請求中最好使用普通文本。



回頁首

結束語

通過本文,您現在可能已經開始對 Ajax 中的 XML 有一些更深的理解了。您知道 Ajax 應用程式不一定要使用 XML,XML 也不是資料轉送中的什麼法寶。還知道從網頁向伺服器發送 XML 不是多麼難的事情。更重要的是,您知道為了確保伺服器能夠處理和響應請求需要做什麼:必須保證伺服器指令碼接受 XML,而且能夠識別用於發送資料的格式。

您還應該非常清楚 XML 對於請求來說並不一定是很好的資料格式。在以後的文章中,您將看到 XML 在某些情況下是有利的,但在多數請求中,它只會降低速度和增加複雜性。因此雖然通常我都會建議您馬上應用在文章中學到的內容,但是對本文來說,我建議您在應用這裡學到的知識時最好三思而後行。XML 請求在 Ajax 應用程式中有自己的價值,但是並不像您所想象的那麼大。

在下一期文章中,我們將討論區伺服器如何使用 XML 做出響應,以及 Web 應用程式如何處理這些響應。令人高興的是,伺服器能夠將 XML 發送回 Web 應用程式,這樣做的理由比較充分,因此那篇文章中的技術細節更實用,目前您只需要知道 XML 為何並非一定是最佳選擇 —— 至少對發送請求而言。您可以嘗試使用 XML 作為請求資料格式實現某些 Web 應用程式,然後再換回普通文本,看看哪種辦法更快更簡單。下一期文章再見。

參考資料

學習

  • 您可以參閱本文在 developerWorks 全球網站上的 英文原文

  • 掌握 Ajax 系列:閱讀本系列以前的文章。
  • XML 文件庫:developerWorks 中國網站 XML 專區提供了各種技術文章和技巧、教程、標準和 IBM 紅皮書。
  • xml.com:如果還不熟悉 XML 編程,這是最容易理解的關於 XML 方方面面的線上資源。
  • 面向 Java 開發人員的 Ajax:構建動態 Java 應用程式”(Philip McCarthy,developerWorks,2006 年 10 月):從 Java 的角度看一看伺服器端的 Ajax。
  • 面向 Java 開發人員的 Ajax:Ajax 的 Java 對象序列化”(Philip McCarthy,developerWorks,2005 年 10 月):從 Java 的角度觀察如何通過網路發送對象並與 Ajax 互動。
  • 使用 AJAX 調用 SOAP Web 服務,第 1 部分:構建 Web 服務客戶機”(James Snell,developerWorks,2006 年 1 月):深入研究這篇較為進階的文章,它介紹了將 Ajax 與現有基於 SOAP 的 Web 服務相整合的有關內容,說明了如何使用 Ajax 設計模式實現一個基於 網頁瀏覽器的 SOAP Web 服務。
  • 全球資訊網同盟 DOM 首頁:請訪問 DOM 相關內容的起點。
  • The DOM Level 3 Core Specification:定義了樞紐文件物件模型,從可用的類型和屬性到 DOM 在不同語言中的用法。
  • ECMAScript language bindings for DOM:如果您是一位 JavaScript 程式員,並希望在代碼中使用 DOM,可能會對 Level 3 Document Object Model Core 定義的這個附錄感興趣。
  • Ajax: A new approach to Web applications”(Jesse James Garrett,Adaptive Path,2005 年 2 月):閱讀有關 Ajax 起源的這篇文章,它是每一位 Ajax 開發人員的必讀之物。
  • developerWorks 技術活動網路廣播:隨時關注這些為技術開發人員準備的軟體研討會和網路廣播。
  • developerWorks 中國網站 Web development 專區:通過這寫文章、教程和論壇等提高您的 Web 開發技能。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.