HTTP定義GET來取得所需的資源,GET用於等冪(idempotent)操作,也就是多次GET操作,都必須傳回相同的結果,GET請求顧名思義,原則上不影響伺服端的狀態。
如果使用傳統表單發送GET請求,GET的請求參數會出現在網址列並更新頁面,但使用非同步物件時,GET的請求參數並不會影響網址列,所以無法讓使用者以請求參數作為書籤之用。
要使用非同步物件透過GET發送請求參數,只要在第二個url參數中以請求參數格式附加,而send()時不傳入引數設為null即可。一個例子如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">
<html>
    <head>
        <meta content="text/html; charset=UTF-8" http-equiv="content-type">
        <script type="text/javascript">
            window.onload = function() {
                var xhr = window.XMLHttpRequest && 
                      (window.location.protocol !== 'file:' 
                          || !window.ActiveXObject) ?
                       function() {
                           return new XMLHttpRequest();
                       } :
                       function() {
                          try {
                             return new ActiveXObject('Microsoft.XMLHTTP');
                          } catch(e) {
                             throw new Error('XMLHttpRequest not supported');
                          }
                       };
                       
                document.getElementById('category').onchange = function() {
                    var request = xhr();
                    request.onreadystatechange = function() {
                        if(request.readyState === 4) {
                            if(request.status === 200) {
                                document.getElementById('book').innerHTML = 
                                    request.responseText;
                            }
                        }
                    };
                    request.open('GET', 'GET-1.php?category=' + this.value + 
                         '&time=' + new Date().getTime()); // 避免GET被快取
                    request.send(null);
                };
            };
        </script>        
    </head>
    <body>
        圖書:<br>
        <select id="category">
            <option>-- 選擇分類 --</option>
            <option value="theory">理論基礎</option>
            <option value="language">程式語言</option>
            <option value="web">網頁技術</option>
        </select><br><br>
        採購:<div id="book"></div>
    </body>
</html>這個例子是連動選單,下一個下拉選單的選項是根據上一個下拉選單的選擇而定,事先不在網頁中寫死第二個選單的選項,而是根據上一個選單所發送的請求參數而定,例如若請求參數為category=theory,則會傳回以下的HTML片段:
<select>
<option value="algorithm">常見演算</option>
<option value="graphic">電腦圖學</option>
<option value="pattern">設計模式</option>
</select>
          
          <option value="algorithm">常見演算</option>
<option value="graphic">電腦圖學</option>
<option value="pattern">設計模式</option>
</select>
當然,直接傳回HTML片段,並不是很好的方式,因為伺服端綁死了客戶端的頁面設計。這個範例只是用來示範GET的請求發送,之後會看到若傳回XML或JSON等其它資料格式,客戶端將有彈性自行決定頁面設計方式。
另外要注意的是,GET請求時若URL相同,瀏覽器可能會作快取(尤其是Internet Explorer),為了避免取得舊的資料,你可以在URL上附加時間戳記,讓每次URL不同,以避免瀏覽器作快取的動作。
Web的世界中,故事往往不會這樣就結束。GET在發送請求時,必須注意編碼的問題,因為/、?、@、空白等字元,在URL中是保留字,RFC 3986 規範了哪些字作為保留字,如果你要在URL表達這些保留字或一些非ASCII字元,必須使用%hexhex編碼形式。例如http://caterpillar.onlyfun.net/add.php?url=https://openhome.cc,若要在URL中表示,必須如此處理:
http://caterpillar.onlyfun.net/add.php?http%3A%2F%2Fopenhome.cc
          
          其中%3A%2F%2F分別就是://三個字元編碼處理後的結果。
在JavaScript中,可以使用encodeURIComponent()為你作這些字元的編碼,編碼後的結果是遵守RFC 3986的規範,然而在RFC 3986之前,HTTP亦規範了GET與POST在發送請求參數時的編碼,大致上也是編碼為%hexhex,不過空白字元是編碼為 + 而不是RFC 3986的%20。如果直接透過瀏覽器按下發送按鈕來送出表單,則瀏覽器會自動處理編碼(依網頁上指定的編碼來處理),並將空白字元編碼為+,但透過非同步物件發送請求參數時,必須自行處理。
發送請求參數時,若使用encodeURIComponent()編碼後,要再將%20取代為+,以符合HTTP的規範。要注意的是,在字串處理方面,JavaScript支援Unicode,內部實作上採用16位元編碼每個字串元素,大致上可視為UCS-2/UTF-16(這當中還有些歷史因素造成的細節,詳見 Effective JavaScript 一書條款七),不過,傳入encodeURIComponent()的字串最後會以UTF-8進行編碼,若將encodeURIComponent()的結果透過非同步物件發送出去,伺服端必須以UTF-8來處理接收到的字串。
如果你沒有透過encodeURIComponent()編碼,就直接透過非同步物件送出非ASCII字元,例如中文,那非同步物件會如何處理編碼,依不同的瀏覽器而有所不同,因此,建議還是使用encodeURIComponent()編碼後將%20取代為+再送出,避免不同瀏覽器的問題。
下面這個範例是GET的另一個示範,在新增書籤時,若URL已重複(已有的書籤是http://caterpillar.onlyfun.net與https://openhome.cc)則以訊息提示:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">
<html>
    <head>
        <meta content="text/html; charset=UTF-8" http-equiv="content-type">
        <script type="text/javascript">
            window.onload = function() {
                var xhr = window.XMLHttpRequest && 
                      (window.location.protocol !== 'file:' 
                          || !window.ActiveXObject) ?
                       function() {
                           return new XMLHttpRequest();
                       } :
                       function() {
                          try {
                             return new ActiveXObject('Microsoft.XMLHTTP');
                          } catch(e) {
                             throw new Error('XMLHttpRequest not supported');
                          }
                       };
                // 組合與編碼請求參數
                function param(obj) {
                    var pairs = [];
                    for(var name in obj) {
                        var pair = encodeURIComponent(name) + '=' + 
                                   encodeURIComponent(obj[name]);
                        pairs.push(pair.replace('/%20/g', '+'));
                    }
                    return pairs.join('&');
                }
                
                document.getElementById('url').onblur = function() {
                    var request = xhr();
                    request.onreadystatechange = function() {
                        if(request.readyState === 4) {
                            if(request.status === 200) {
                                var message = '';
                                if(request.responseText === 'urlExisted') {
                                    message = 'URL 已存在';
                                }
                                document.getElementById('message')
                                        .innerHTML = message;
                            }
                        }
                    };
                    var params = param(
                       { url : document.getElementById('url').value }
                    );
                    request.open('GET', 'GET-2.php?' + params +
                         '&time=' + new Date().getTime()); // 避免GET被快取
                    request.send(null);
                };
            };
        </script>        
    </head>
    <body>
        新增書籤:<br>
        網址:<input id="url" type="text">
        <span id="message" style="color:red"></span><br>
        名稱:<input type="text">
    </body>
</html>若URL已存在,則傳回'urlExisted'的字串,此時將訊息設定為「URL 已存在」。

