AJAX 入門

yeahokay發表於2007-07-12

資料來源 :

The following examples had been tested on Mozilla's Firefox and Microsoft's IE. The document is provided as is. You are welcomed to use it for non-commercial purpose.

  • 何謂 AJAX?
  • 第一個範例
  • 使用 AJAX 的時機
  • AJAX: Example II
  • 練習題
  • 由 XMLHttpRequest 送出中文資料給 Tomcat
  • 利用 Dojo Toolkit
  • 利用 Yahoo! User Interface Library
  • [@more@]

    何謂 AJAX?

    AJAX 是 Asynchronous JavaScript And XML 的簡寫,它的裡面非常類似 Dynamic HTML(或者 DHTML),主要的目的在於提高網頁的互動性(interactivity),速度(speed),以及可用性(usability)。想想看,如果我們能使一個網頁的互動方式可以達到類似 Microsoft Office 的境界,那麼網頁的可用性可以達到另一個層次。

    其實,這個概念並不是很新,只是這樣的技巧被大量的應用於 Google 的網頁之後,如 Gmail、Google Maps、和 Google Suggest 等,才被重視,而第一個提出 AJAX 這個名詞的就是 。利用類似技巧的公司還有 Writely、Kiko 等。這樣的概念,開始的人們對於網頁是否會取代 desktop applications 進行討論,而又進一步的延伸出 的討論。

    AJAX 也不是一項單獨的技術,它是由一堆現有的技術所組成,它的組成技術有:

    1. XHTML(或者 HTML)加上 CSS 來作為資料的呈現。
    2. 利用 DOM 以及 Javascript 來進行存取資料(大多為 XML)的處理。
    3. 利用 XMLHttpRequest 物件與遠端的 web server 進行非同步的資料交換。

    第一個範例

    在之前的 JavaScript 入門中,我們已經給了 HTML 和 CSS 以及 DOM 的應用範例,因此我們在第一個範例中,介紹 XMLHttpRequest 的用法。這個範例試圖從遠端取得臺中地區的行政區域檔

    取得臺中的行政區域

    • 首先,在跟遠端伺服器要求檔案以前,我們需要產生 XMLHttpRequest 的物件。跟所有的 JavaScript 問題一樣,在產生 XMLHttpRequest 的物件,Mozilla 和 Internet Explorer 也有不同的語法,因此處理 AJAX 的 JavaScript 需要判斷你所使用的 browser 是哪一種。
          if (window.XMLHttpRequest) { // Mozilla, Safari,...
            http_request = new XMLHttpRequest();
          } else if (window.ActiveXObject) { // IE
            try {
              // 新版的 IE
              http_request = new ActiveXObject("Msxml2.XMLHTTP");
            } catch (e) {
              try {
                // 舊版的 IE
                http_request = new ActiveXObject("Microsoft.XMLHTTP");
              } catch (e) {}
            }
          }
      
    • 有了 XMLHttpRequest 的物件之後,就是向遠端要求檔案,在這個範例中,我們要取得的檔案名稱是 taichung.xml。
      http_request.open('GET', 'taichung.xml', true);
      http_request.send(null);
      
      1. open() 的第一個引數是 HTTP 的方法,看你的需要,以及 web server 支援的情形,你可以使用 GET、POST、或者 HEAD。建議使用大寫以符合 HTTP 的標準。
      2. open() 的第二個引數是你希望取得的資源的 URL。由於安全的機制,你只能從同一個 web server 上取得資源。
      3. open() 的第三個引數是代表這個呼叫是不是非同步(即 AJAX 的第一個 A)。因此,在大部分的情形下都是設為 true 代表在跟遠端取得資源的同時,browser 可以繼續執行 Javascript 的內容。這個時候其實有兩件事情同時在進行,一個是從遠端取得資料,另一個是繼續執行 JavaScript 的內容,或者使用者可以繼續處理網頁上的資料,這也就是非同步的定義。
      4. 如果使用 GET 的方式,send() 的引數為 null。如果使用 POST 的方式,我們除了要設定 MIME 的型別(如下)之外,
        http_request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        
        我們還需要傳遞 HTML form 內的資料,例如,
        http_request.send('name=value&anothername=othervalue&so=on');
        

    • 既然是非同步的進行方式,在 open() 以及 send() 之前,我們必須先設定一些事件處理的函式來處理如"已經取得資料"的事件。定義事件處理函式的格式如下:
      http_request.onreadystatechange = function(){
          // do the thing
      };
      
    • 一般來說,事件處理函式首先要檢查的是目前 web server 對於我們之前送出去的 http_request 的處理狀態為何。處理狀態的屬性名稱為 readyState,它所有可能的值為
      • 0 (尚未初始化; 還沒呼叫 open())
      • 1 (載入中; http_request 已經設定好了,但是還沒呼叫 send())
      • 2 (載入完成; http_request 已經送給 server 了,server 已經開始 處理了,你可以取得 content header 了。)
      • 3 (可以互動的; http_request 已經部份完成了,所以有可能取得 部份處理完的資料)
      • 4 (完成的; compelte)
      在大部分的情形下,我們只對已經完成的狀態有興趣,所以我們的程式碼的格式如下:
      if (http_request.readyState == 4) {
          // everything is good, the response is received
      } else {
          // still not ready
      }
      
    • web server 的處理結束之後,會回傳一個處理結果,例如,我們的要求完成了,但是處理結果卻是"找不到檔案"。因此,我們的程式還需要檢查處理結果,處理結果是放在 status 這個屬性內,因此檢查處理結果的程式碼如下:
      if (http_request.status == 200) {
          // 可以依照我們的需求來處理 xml 的資料了
      } else {
          // 404 代表檔案不存在,500 代表處理錯誤(Internal Server Error)
          // 自行決定要如何處理錯誤的情形
      }
      
    • 最後,就是接收來自 web server 的資料,http_request 提供兩種方式來存取資料:
      • http_request.responseText 也就是 web server 回傳的資料是以一串的文字,你需要利用字串的處理函式。
      • http_request.responseXML 也就是 web server 回傳的資料是一份 XMLDocuemnt 的物件,你可以利用 JavaScript 的 DOM APIs 來存取這份 XML 物件。

    • 這個範例的完整原始碼:
      
             取得臺中的行政區域 
      
      
    • Gecko DOM Reference Gecko 是 Mozilla、Firefox、Opera 等瀏覽器的引擎,你需要這個檔案來檢查有哪些 DOM 的 APIs 可以使用。
    • .

    使用 AJAX 的時機

    想想看,像 Google Maps 的使用中,browser 與 web server 之間需要傳遞非常大量的圖形資料,如果利用傳統的同步方式,在全部的圖形下載完成之前,我們沒辦法對網頁進行操作,而使用者點選往左、往右的按鈕後,使用者又得等待另一次的圖形傳遞。反之,如果我們可以在使用者操作的時候,非同步的下載其它圖形呢?這樣速度會變快,也不必一再的重複 reload 網頁。(註:依據 IBM McLaughlin 的說法,這些可以動態出現不同內容的地方,經常是由
    或者 所定義。)

    當 AJAX engine 接收使用者全部或者部份的 form data 之後,AJAX engine 會跟 web server 連絡並由 web server 處理完成,並將完成的資料回傳給 AJAX engine,然後再由 AJAX engine 將成果動態的呈現在網頁上。這些過程,使用者完全不會感受到,而且由於是非同步的,網頁不會停止接收使用者的操作。

    練習題

    • 可以寫一個網頁讓使用者決定輸入 URL 或者讀取伺服器端的 XML 檔,如果使用者選擇 URL,則網頁出現一個文字欄位讓使用者輸入 URL;若使用者選擇讀取伺服器端的 XML 檔,則網頁出現下拉式選單顯示伺服器端所有的 XML 檔的檔名(須能自動產生),按確定後,出現 XML 檔案的內容。
      • 為 AJAX 的網頁,而使用到的 Java Servlets 為 和 。
    • 將我們的行政區域的範例轉換成與後端程式的連結,例如,行政區域是由一個 PHP 或者 Java Servlet 跟資料庫管理系統取得的資料。
    • 總共有五個圖,當載入網頁的時候只載入中間那個圖,而其他四個圖(各為上、下、左、右)利用 AJAX 的非同步方式載入,當某一個圖(例如右圖)完成載入的時候,則出現可以點選該圖的連結。

    由 XMLHttpRequest 送出中文資料給 Tomcat

    在嘗試 Dojo 和 Yahoo! User Interface Library (YUI) 的時候,才突然發現之前的 AJAX 範例都沒有從 XMLHttpRequest 傳送中文的資料給遠端的 Tomcat servlet。而發現的原因在於為 Dojo 和 YUI 所寫的程式中,其中一個範例是由 browser 送出一個中文的(Big5)欄位資料到遠端的 Tomcat servlet 處理,而處理的結果卻是亂碼。這樣子一來就打亂了我的休假,連續兩個晚上測到凌晨一、兩點(對一個老人來說,是很大的折磨)。這兩天找了不少資料,目前以 的文章比較有參考價值。尤其,OC'onner 的文章直接說明目前的傳送以及 encoding 的方式並沒有標準,完全要看你所使用的工具而定。看了這個說明之後,測試的方向就比較明確一些。大概需要檢查的細節有:
    • 由 XMLHttpRequest 送出去的 URL:如果 URL 包含 Big5 的資料,XMLHttpRequest 會不會 encode,而且又是以何種方式 encode?
    • server 是如何解讀收到的 URL:目前知道 Tomcat (我的主要 servlet 開發平臺)是採用 ISO-8859-1 編碼方式來接收,因此解碼的方式可以用 ISO-8859-1 來進行。但是,如果 browser 送過來的資料是以 UTF-8 編碼,那要怎麼辦呢?
    目前,已經找出 Microsoft IE 6.x 以及 Firefox 1.5.x 的解決方案了。測試出來的情形整理如下:(在沒有足夠的資訊之下,很難明確的瞭解為什麼會有這樣的 encode/decode 結果)
    • IE 6.x:
      • 若 Javascript 對中文資料 encodeURIComponent(),則 servlet 需要對接收到的資料先以 ISO-8859-1 解出來之後,以 UTF-8 編碼出來。
      • 若 Javascript 不對中文資料進行 encodeURIComponent(),則 servlet 需要對接收到的資料先以 ISO-8859-1 解出來之後,以 Big5 編碼出來。
    • Firefox 1.5.x:不論 browser 是否對中文資料 encodeURIComponent(),servlet 需要對接收到的資料 先以 ISO-8859-1 解出來之後,以 UTF-8 編碼出來。
    從剛剛的討論結果可以知道 XMLHttpRequest 在送出要求之前,我們需要對 Big5 的資料進行編碼(也就是 encodeURIComponent),而送到 Tomcat servlet 之後, servlet 必須先以 ISO-8859-1 的方式接收之後,再依據 UTF-8 的方式解碼使資料回到 Big5 的格式,你可以連結 。
    
    
    
    姓名:
    遠端的 servlet 程式為
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.*;
    
    public class Hello extends HttpServlet {
      public void doGet(HttpServletRequest req, HttpServletResponse res)
             throws ServletException, IOException
      {
        res.setContentType("text/plain;charset=Big5");
        PrintWriter output = res.getWriter();
    
        String msg = req.getParameter("name");
        
        msg = new String(msg.getBytes("ISO-8859-1"), "UTF-8");
        
    
        StringBuffer buf = new StringBuffer();
        buf.append("Hello " + msg);
        buf.append(" , 歡迎使用 AJAX");
        output.println(buf.toString());
        output.close();
      }
    }
    

    利用 Dojo Toolkit

    想要寫出一個擁有豐富介面的 AJAX 程式,其實有一定的困難。為了讓我們的 AJAX 程式具有"企業級"的水準,我們可以借用一些 AJAX 的程式庫。目前非常受歡迎、而且又是 open source 的 AJAX 工具有 以及 Yahoo! User Interface Library

    利用 Yahoo! User Interface Library

    • 好的 Tutorials:
    • 我的測試網頁


    Last Updated: Tuesday, 12-Jun-2007 11:06:01 CST
    Written by: Eric Jui-Lin Lu

    來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/786540/viewspace-926180/,如需轉載,請註明出處,否則將追究法律責任。

    相關文章