掌握 Ajax,第 11 部分: 服務器端的 JSON

文檔選項
將打印機的版面設置成橫向打印模式

打印本頁

將此頁作爲電子郵件發送

將此頁作爲電子郵件發送



級別: 高級

Brett D. McLaughlin, Sr. ([email protected]), 作家兼編輯, O'Reilly Media, Inc.

2007 年 8 月 28 日

本系列最近發表的一篇文章中,您已經瞭解瞭如何將 JavaScript 對象轉變成 JSON 格式。這種格式很容易用於發送(和接收)與對象甚至對象數組對應的數據。在 本系列 的最後一篇文章中,您將會學習如何處理以 JSON 格式發送到服務器的數據以及如何使用相同格式對腳本進行回覆。

JSON 的真正價值

正如在 本系列上一篇文章 中所描述的那樣,JSON 是適用於 Ajax 應用程序的一種有效格式,原因是它使 JavaScript 對象和字符串值之間得以快速轉換。由於 Ajax 應用程序非常適合將純文本發送給服務器端程序並對應地接收純文本,相比不能生成文本的 API,能生成文本的 API 自然更可取;而且,JSON 讓您能夠處理本地 JavaScript 對象,而無需爲如何表示這些對象多費心思。

developerWorks Ajax 資源中心
請訪問 Ajax 資源中心,這是有關 Ajax 編程模型信息的一站式中心,包括很多文檔、教程、論壇、blog、wiki 和新聞。任何關於 Ajax 的新信息都能在這裏找到。

XML 也可以提供文本方面的類似益處,但用於將 JavaScript 對象轉換成 XML 的幾個現有 API 沒有 JSON API 成熟;有時,您必須在創建和處理 JavaScript 對象時格外謹慎以確保所進行的處理能與所選用的 XML 會話 API 協作。但對於 JSON,情況就大不相同:它能處理幾乎所有可能的對象類型,並會返回給您一個非常好的 JSON 數據表示。

因此,JSON 的最大價值在於可以將 JavaScript 真的作爲 JavaScript 而非數據格式語言進行處理。您所學到的所有有關使用 JavaScript 對象的技巧都可以應用到代碼中,而無需爲如何將這些對象轉變成文本而多費心思。這之後,可以進行如下所示的簡單 JSON 方法調用:

String myObjectInJSON = myObject.toJSONString();

現在就可以將結果文本發送給服務器了。





回頁首


將 JSON 發給服務器

將 JSON 發給服務器並不難,但卻至關重要,而且還有一些重要的選擇要做。但是,一旦決定使用 JSON,所要做的這些選擇就會十分簡單而且數量有限,所以您需要考慮和關注的事情不多。重要的是能夠將 JSON 字符串發送給服務器,而且最好能做到儘快和儘可能簡單。

通過 GET 以名稱/值對發送 JSON

將 JSON 數據發給服務器的最簡單方法是將其轉換成文本,然後以名稱/值對的值的方式進行發送。請務必注意,JSON 格式的數據是相當長的一個對象,看起來可能會如清單 1 所示:


清單 1. JSON 格式的簡單 JavaScript 對象
                
var people =  { "programmers": [    { "firstName": "Brett", "lastName":"McLaughlin",
"email": "[email protected]" },    { "firstName": "Jason", "lastName":"Hunter",
"email": "[email protected]" },    { "firstName": "Elliotte", "lastName":"Harold",
"email": "[email protected]" }   ],  "authors": [    { "firstName": "Isaac", 
"lastName": "Asimov", "genre": "science fiction" },    { "firstName": "Tad", 
"lastName": "Williams", "genre": "fantasy" },    { "firstName": "Frank", 
"lastName": "Peretti", "genre": "christian fiction" }   ],  "musicians": [    
{ "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },   
{ "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }   ]  }

如果要以名稱/值對將其發送到服務器端,應該如下所示:

var url = "organizePeople.php?people=" + people.toJSONString();
xmlHttp.open("GET", url, true);
xmlHttp.onreadystatechange = updatePage;
xmlHttp.send(null);

這看起來不錯,但卻存在一個問題:在 JSON 數據中會有空格和各種字符,Web 瀏覽器往往要嘗試對其繼續編譯。要確保這些字符不會在服務器上(或者在將數據發送給服務器的過程中)引起混亂,需要在 JavaScript escape() 函數中做如下添加:

var url = "organizePeople.php?people=" + escape(
people.toJSONString()
);
request.open("GET", url, true);
request.onreadystatechange = updatePage;
request.send(null);

該函數可以處理空格、斜線和其他任何可能影響瀏覽器的內容,並將它們轉換成 Web 可用字符(比如,空格會被轉換成 %20,瀏覽器並不會將其視爲空格處理,而是不做更改,將其直接傳遞到服務器)。之後,服務器會(通常自動)再把它們轉換回它們傳輸後的本來 “面目”。

這種做法的缺點有兩個:

  • 在使用 GET 請求發送大塊數據時,對 URL 字符串有長度限制。雖然這個限制很寬泛,但對象的 JSON 字符串表示的長度可能超出您的想象,尤其是在使用極其複雜的對象時更是如此。
  • 在跨網絡以純文本發送所有數據的時候,發送數據面臨的不安全性超出了您的處理能力。

簡言之,以上是 GET 請求的兩個限制,而不是簡單的兩個與 JSON 數據相關的事情。在想要發送用戶名和姓之外的更多內容,比如表單中的選擇時,二者可能會需要多加註意。若要處理任何機密或極長的內容,可以使用 POST 請求。

利用 POST 請求發送 JSON 數據

當決定使用 POST 請求將 JSON 數據發送給服務器時,並不需要對代碼進行大量更改,如下所示:

var url = "organizePeople.php?timeStamp=" + new Date().getTime();
request.open("POST", url, true);
request.onreadystatechange = updatePage;
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.send(people.toJSONString());

這些代碼中的大部分,您都在 “ 掌握 Ajax,第 3 部分:Ajax 中的高級請求和響應” 中見過,應該比較熟悉,第 3 部分重點介紹瞭如何發送 POST 請求。請求使用 POST 而非 GET 打開,而且 Content-Type 頭被設置爲讓服務器預知它能得到何種數據。在這種情況下,即爲 application/x-www-form-urlencoded,它讓服務器知道現在發送的是文本,正如它從常規的 HTML 表單中得到的一樣。

另一個簡單提示是 URL 的末尾追加了時間。這就確保了請求不會在它第一次被髮送後即緩存,而是會在此方法每次被調用後重新創建和重發;此 URL 會由於時間戳的不同而稍微有些不同。這種技巧常被用於確保到腳本的 POST 每次都會實際生成新請求且 Web 服務器不會嘗試緩存來自服務器的響應。

JSON 就只是文本

不管使用 GET 還是 POST,關鍵之處在於 JSON 就只是文本。由於不需要特殊編碼而且每個服務器端腳本都能處理文本數據,所以可以輕鬆利用 JSON 並將其應用到服務器。假如 JSON 是二進制格式的或是一些怪異的文本編碼,情況就不這麼簡單了;幸好 JSON 只是常規的文本數據(正如腳本能從表單提交中所接收到的數據,在 POST 段和 Content-Type 頭中亦可以看出),所以在將數據發送到服務器時無需太費心。





回頁首


在服務器上解釋 JSON

一旦您編寫完客戶端 JavaScript 代碼、允許用戶與 Web 表單和 Web 頁的交互、收集發送給服務器端程序以做處理所需的信息,此時,服務器就成爲了應用程序(如果調用了異步使用的服務器端程序,則可能是我們認爲的所謂的 “Ajax 應用程序”)中的主角。在此時,您在客戶端所做的選擇(比如使用 JavaScript 對象,然後將其轉換成 JSON 字符串)必須要與服務器端的選擇相匹配,比如使用哪個 API 解碼 JSON 數據。

處理 JSON 的兩步驟

不管在服務器端使用何種語言,在服務器端處理 JSON 基本上就需要兩個步驟。

  1. 針對編寫服務器端程序所用的語言,找到相應的 JSON 解析器/工具箱/幫助器 API。
  2. 使用 JSON 解析器/工具箱/幫助器 API 取得來自客戶機的請求數據並將數據轉變成腳本能理解的東西。

以上差不多就是目前所應瞭解的大致內容了。接下來,我們對每個步驟進行較爲詳細的介紹。

尋找 JSON 解析器

尋找 JSON 解析器或工具箱最好的資源是 JSON 站點(有關鏈接,請參閱 參考資料)。在這裏,除了可以瞭解此格式本身的方方面面之外,還可以通過各種鏈接找到 JSON 的各種工具和解析器,從 ASP 到 Erlang,到 Pike,再到 Ruby,應有盡有。您只需針對自己編寫腳本所用的語言下載相應的工具箱即可。爲了讓服務器端腳本和程序能夠使用此工具箱,可以根據情況對其進行選擇、擴展或安裝(如果在服務器端使用的是 C#、PHP 或 Lisp,則可變性更大)。

例如,如果使用的是 PHP,可以簡單將其升級至 PHP 5.2 並用它完成操作;在 PHP 這個最新版本默認包含了 JSON 擴展。實際上,那也是在使用 PHP 時處理 JSON 的最好方法。如果使用的是 Java servlet,json.org 上的 org.json 包顯然就是個不錯的選擇。在這種情況下,可以從 JSON Web 站點下載 json.zip 並將其中包含的源文件添加到項目構建目錄。編譯完這些文件後,一切就就緒了。對於所支持的其他語言,同樣可以使用相同的步驟;使用何種語言取決於您對該語言的精通程度,最好使用您所熟悉的語言。

使用 JSON 解析器

一旦獲得了程序可用的資源,剩下的事就是找到合適的方法進行調用。比如,假設爲 PHP 使用的是 JSON-PHP 模板:

// This is just a code fragment from a larger PHP server-side script
require_once('JSON.php');

$json = new Services_JSON();

// accept POST data and decode it
$value = $json->decode($GLOBALS['HTTP_RAW_POST_DATA']);

// Now work with value as raw PHP

通過該模板,可將獲得的所有數據(數組格式的、多行的、單值的或 JSON 數據結構中的任何內容)轉換成原生 PHP 格式,放在 $value 變量中。

如果在 servlet 中使用的是 org.json 包,則會使用如下代碼:

public void doPost(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {

  StringBuffer jb = new StringBuffer();
  String line = null;
  try {
    BufferedReader reader = request.getReader();
    while ((line = reader.readLine()) != null)
      jb.append(line);
  } catch (Exception e) { //report an error }

  try {
    JSONObject jsonObject = new JSONObject(jb.toString());
  } catch (ParseException e) {
    // crash and burn
    throw new IOException("Error parsing JSON request string");
  }

  // Work with the data using methods like...
  // int someInt = jsonObject.getInt("intParamName");
  // String someString = jsonObject.getString("stringParamName");
  // JSONObject nestedObj = jsonObject.getJSONObject("nestedObjName");
  // JSONArray arr = jsonObject.getJSONArray("arrayParamName");
  // etc...
}

可以參考 org.json 包文檔(有關鏈接,請參閱 參考資料 部分)以瞭解詳細信息。(注意:如果想要獲得有關 org.json 或其他 JSON 工具箱的詳細信息,可以給我發電子郵件。您的來信會有助於我決定將來大概寫的內容!)





回頁首


結束語

至此,您應該從技術角度對如何在服務器端處理 JSON 有了基本的把握。本篇文章和本系列的 第 10 部分 不僅提供了技術層面的幫助,而且還向您展示了 JSON 是一種多麼靈活、強大的數據格式。即使您不會在每個應用程序中都使用 JSON,但優秀的 Ajax 和 JavaScript 程序員的工具箱中總少不了 JSON 以備不時之需。

我當然很希望能夠分享您的 JSON 使用經驗以及您對何種語言更善於在服務器端處理 JSON 數據的高見。您可以訪問 Java 和 XML 新聞組(有關鏈接,請參閱 參考資料 部分)跟我聯繫。享受 JSON 和文本數據格式的樂趣吧。



參考資料

學習

討論


關於作者

Photo of Brett McLaughlin

Brett McLaughlin 從 Logo 時代就開始使用計算機。(還記得那個小三角嗎?)近年來,他已經成爲 Java 和 XML 社區最著名的作者和程序員之一。他曾經在 Nextel Communications 實現過複雜的企業系統,在 Lutris Technologies 編寫過應用服務器,最近,他在 O'Reilly Media, Inc. 繼續撰寫和編輯這方面的圖書。Brett 即將出版的新書 Head Rush Ajax 爲 Ajax 帶來了獲獎的革命性 Head First 方法。最近的著作 Java 1.5 Tiger: A Developer's Notebook 是關於 Java 技術最新版本的第一本書。經典的 Java and XML 依然是在 Java 語言中使用 XML 技術的權威著作。



 來自 http://www.ibm.com/developerworks/cn/web/wa-ajaxintro11.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章