XMLHttpRequest對象
除IE以外所有的瀏覽器都支援直接使用XMLHttpRequest對象。而IE是通過建立ActiveXObject來建立類似的對象。這裡給出一種封裝方法使得IE5以上的IE版本也能具有XMLHttpRequest對象,這樣我們在使用XMLHttpRequest對象的時候可以使用同一的建立方法:
(來自《精通JavaScript》)
if (typeof XMLHttpRequest == 'undefined') {
XMLHttpRequest = function() {
return new ActiveXObject(
navigator.userAgent.indexOf("MSIE 5") >= 0 ? "Microsoft.XMLHTTP" : "Msxml2.XMLHTTP"
);
}
}
發送請求
GET請求
只支援發送序列化資料(下文會有具體例子)
以下是GET請求發送的簡單例子
// 建立對象
var xml = new XMLHttpRequest();
// 初始化
xml.open("GET", "test.html", true);
// 發送
xml.send();
POST請求
POST請求發送方式與GET請求發送方式類似,下文具體。
請求狀態
我們可以通過XMLHttpRequest對象中的readyState監視請求的狀態。readyState是一個整型值,各自代表的狀態是:
0 = 未初始化
1 = 已初始化 (有些書將此狀態注為下載,實際測試發現初始化後、未發送請求之前,狀態已經修改為1)
2 = 下載已完成
3 = 互動的(響應被部分接收)
4 = 完成
在我們的Ajax應用中,一般只需要使用4-完成狀態。
當請求狀態變化時,會觸發onreadystatechange事件,我們處理ajax響應就是為這個事件綁定處理函數。
用戶端完整樣本
以下結合上述內容,寫一個完整的用戶端ajax樣本
var xml = new XMLHttpRequest();
// 未初始化 xml.readyState 為 0
xml.open("POST", "test.html", true);
// 已初始化 xml.readyState 為 1
xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
if (xml.overrideMimeType)
xml.setRequestHeader("Connection", "close");
// 綁定狀態變化事件處理函數
xml.onreadystatechange = function() {
alert(xml.readyState);
}
xml.send("abc");
資料對象的格式
根據資料對象的特點,我們可以選擇合適的發送方式。
序列化
利用HTTP GET標準請求,即類似: http://www.zhengchuyu.cn/?name=zcy&nick=donald 的傳輸方式。
我們需要有一個序列化函數,並且是針對錶單元素和索引值對對象設計的。(不能序列化多選按鈕)
function serialize(a) {
var s = [];
if (a.constructor == Array) {
// 表單元素數組
for (var i = 0; i < a.length; i++) {
s.push( a[i].name + "=" + encodeURIComponent(a[i].value));
}
}
else {
// 索引值對對象
for (var j in a)
s.push(j + "=" + encodeURIComponent(a[j]));
}
return s.join("&");
}
GET請求發送序列化資料
var xml = new XMLHttpRequest();
xml.open("GET", "test.html?" + serialize(data), true);
xml.send();
POST請求發送序列化資料
var xml = new XMLHttpRequest();
xml.open("POST", "test.html", true);
// 設定content-type頭部資訊,告訴伺服器如何解析我們發送的資料
xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// 保證瀏覽器發送的序列化資料長度正確
if (xml.overrideMimeType)
xml.setRequestHeader("Connection", "close");
// 序列化資料發送
xml.send(serialize(data));
xml
後文詳述。
json
後文詳述
HTTP響應
上文已經提到可以通過判斷readyState的值得知請求狀態,我們可以知道用戶端是否已經獲得了伺服器響應。但是伺服器並不是每一次都能正常響應,這時我們需要通過伺服器響應代碼(儲存在返回結果對象的status變數中)判斷響應情況。
狀態代碼
成功響應 200~300
未修改響應 304
本地檔案 無狀態碼
另外有一個特殊情況(來自《精通JavaScript》,沒有驗證),Safari瀏覽器中,如果文檔自上次請求未曾修改過,會返回狀態代碼“undefined”,比較怪異。
以下給出一判斷XMLHttpRequest對象是否處於成功響應狀態的相容函數
function httpSuccess(r) {
try {
return !r.status && location.protocol == "file:"
|| (r.status >= 200 && r.status < 300)
|| r.status == 304
|| navigator.userAgent.indexOf("Safari") >= 0 && typeof r.status == "undefined";
}
catch(e) {
return false;
}
}
逾時檢查
逾時檢查比較簡單,就是用一個變數記錄是否逾時,在send發送之前用一個setTimeout設定在某個時間段後把該變數標記為逾時,並在狀態改變響應函數中檢測這一變數就行了。
伺服器返回資料
伺服器可以返回任何格式的資料。一般比較常用的是XML、HTML、JavaScript/JSON。
擷取資料
擷取資料通過XMLHttpRequest的兩個重要屬性:responseXML和responseText。
responseXML 可以擷取XML,即伺服器明確指出“Content-Type:text/xml”時才可以由這個屬性擷取。
responseText 可以擷取HTML和JavaScript類型的資料。
指定類型解析資料
以下是一個按指定類型解析資料的函數
(來自《精通JavaScript》,為了便於理解,稍有改動)
// type可選值:xml, script, text, html 預設值:空
function httpData(r, type) {
var ct = r.getResponseHeader("content-type");
var data = !type && ct && ct.indexOf("xml") >= 0;
data = (type == "xml" || data) ? r.responseXML : r.responseText;
if (type == "script")
eval.call(window, data);
return data;
}