AJAX 上手篇
第一步 – 說聲「請(qǐng)」 (又稱為「怎么發(fā)出 XMLHttpRequest」)
為了用 JavaScript 對(duì)服務(wù)器發(fā)送 HTTP 要求,你必須先以相關(guān)的類別(class)制出實(shí)體(instance)。Internet
Explorer 首先以 ActiveX 對(duì)象方式提供 XMLHTTP
類別,而 Mozilla、Safari及其它瀏覽器則隨后以 XMLHttpRequest
類別支持此 ActiveX 對(duì)象中的類別及屬性。
因此,如果想跨瀏覽器,那么可以這么寫:?
if
?(window.XMLHttpRequest)?{?
//
?Mozilla,?Safari,?
????http_request?
=
?
new
?XMLHttpRequest();
}?
else
?
if
?(window.ActiveXObject)?{?
//
?IE
????http_request?
=
?
new
?ActiveXObject(
"
Microsoft.XMLHTTP
"
);
}
(由于這段程序僅供說明,所以是采最簡(jiǎn)方式寫出。本文第三步中有另一種我們比較常用的寫法。)
有些版本的 Mozilla 瀏覽器在服務(wù)器送回的數(shù)據(jù)未含 XML mime-type 文件頭(header)時(shí)會(huì)出錯(cuò)。為了避免這個(gè)問題,你可以用下列方法覆寫服務(wù)器傳回的檔頭,以免傳回的不是text/xml
。
http_request?
=
?
new
?XMLHttpRequest();
http_request.overrideMimeType('text
/
xml');
接下來是要決定服務(wù)器傳回資料后的處理方式,此時(shí)你只要以 onreadystatechange
這個(gè)屬性指明要處理傳回值的
JavaScript 函式名稱即可,例如:
http_request.onreadystatechange?
=
?nameOfTheFunction;
注意,指定的函式名稱后不加括號(hào)也沒有參數(shù)。除了指定函式名稱外,你也能用 Javascript 實(shí)時(shí)定義函式的方法來定一個(gè)新的處理函式,如下:
http_request.onreadystatechange?
=
?
function
(){
????
//
?做些事
};
決定處理方式之后你得確實(shí)發(fā)出 request,此時(shí)需叫用 HTTP request 類別的 open()
及 send()
方法,如下:
http_request.open('GET',?'http:
//
www.example.org/some.file',?true);
http_request.send(
null
);
-
open()
的第一個(gè)參數(shù)是
???? HTTP request 的方法,也就是從
???? GET、POST、HEAD 中擇一使用,亦可用你主機(jī)上支持的方式。為遵循 HTTP 標(biāo)準(zhǔn),請(qǐng)記得這些方法都是大寫,不然有的瀏覽器(如 Firefox)或許不會(huì)理你。其它 HTTP request 可以支持的方法列表請(qǐng)參考
???? W3C 規(guī)格書 (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html)。
- 第二個(gè)參數(shù)是目標(biāo) URL。基于安全考慮,你不能叫用同網(wǎng)域以外的網(wǎng)頁(yè)。如果網(wǎng)域不同,則叫用
???? open()
時(shí)會(huì)出現(xiàn)「權(quán)限不足,拒絕存取」那類的錯(cuò)誤。通常大伙會(huì)犯的錯(cuò)誤多為在 domain.tld 網(wǎng)的網(wǎng)站下呼叫 www.domain.tld 中的網(wǎng)頁(yè),僅是一點(diǎn)點(diǎn)差別都不行。
????
- 第三個(gè)參數(shù)決定此 request 是否不同步進(jìn)行,如果設(shè)定為
???? TRUE
則即使服務(wù)器尚未傳回?cái)?shù)據(jù)也會(huì)繼續(xù)執(zhí)行其余的程序,這也就是 AJAX 中第一個(gè) A 代表的意義。
send()
的參數(shù)在以 POST 發(fā)出 request 時(shí)可以是任何想傳給服務(wù)器的東西,而數(shù)據(jù)則以查詢字符串的方式列出,例如:
?
name
=
value
&
anothername
=
othervalue
&
so
=
on
不過如果你想要以 POST 方式傳送數(shù)據(jù),則必須先將 MIME 型態(tài)改好,如下:
http_request.setRequestHeader('Content
-
Type',?'application
/
x
-
www
-
form
-
urlencoded');
否則服務(wù)器就不會(huì)理你傳過來的數(shù)據(jù)了。
第二步 – 「就上咩!」(又稱為「處理服務(wù)器傳回的數(shù)據(jù)」)
傳出 request 時(shí)必須提供處理傳回值的函式名稱。
http_request.onreadystatechange?
=
?nameOfTheFunction;
////////////////////////////////////////////////////////////////////
//但是,F(xiàn)ireFox 對(duì)onreadyStateChange沒有反應(yīng),怎么辦,這個(gè)方法不能用在
//FireFox 中,有沒有其它的方法?
//??????Added by www.besook.com 2006-03-19
//////////////////////////////////////////////////////////////
那么來看看這個(gè)函式該做些什么。首先,它必須檢查 request 目前的狀態(tài):如果狀態(tài)值為 4 代表服務(wù)器已經(jīng)傳回所有信息了,便可以開始解析所得信息。
if
?(http_request.readyState?
==
?
4
)?{
????
//
?一切?ok,?繼續(xù)解析
}?
else
?{
????
//
?還沒完成
}
readyState
所有可能的值如下:
- 0 (還沒開始)
- 1 (讀取中)
- 2 (已讀取)
- 3 (信息交換中)
- 4 (一切完成)
(資料來源: MSDN (http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/readystate_1.asp))
接下來要檢查服務(wù)器傳回的 HTTP 狀態(tài)碼。所有狀態(tài)碼列表可于 W3C
網(wǎng)站 (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)上查到,但我們要管的是200 OK
這種狀態(tài)。
if
?(http_request.status?
==
?
200
)?{
????
//
?萬(wàn)事具備
}?
else
?{
????
//
?似乎有點(diǎn)問題,或許服務(wù)器傳回了?404?(查無此頁(yè))?或者?500?(內(nèi)部錯(cuò)誤)?什么的
}
檢查傳回的 HTTP 狀態(tài)碼后,要怎么處理傳回的數(shù)據(jù)就由你決定了。有兩種存取數(shù)據(jù)的方式:
-
http_request.responseText
– 這樣會(huì)把傳回值當(dāng)字符串用
????
-
http_request.responseXML
– 這樣會(huì)把傳回值視為
???? XMLDocument
對(duì)象,而后可用
???? JavaScript DOM 相關(guān)函式處理
第三步 - 萬(wàn)事俱備 - 簡(jiǎn)單范例
好,接著就做一次簡(jiǎn)單的 HTTP 范例,演示方才的各項(xiàng)技巧。這段 JavaScript 會(huì)向服務(wù)器要一份里頭有「I'm
a test.」字樣的 HTML 文件(test.html
),而后以 alert()
將文件內(nèi)容列出。
<
script?type
=
"
text/javascript
"
?language
=
"
javascript
"
>
????
var
?http_request?
=
?
false
;
????
function
?makeRequest(url)?{
????????http_request?
=
?
false
;
????????
if
?(window.XMLHttpRequest)?{?
//
?Mozilla,?Safari,
????????????http_request?
=
?
new
?XMLHttpRequest();
????????????
if
?(http_request.overrideMimeType)?{
????????????????http_request.overrideMimeType('text
/
xml');
????????????}
????????}?
else
?
if
?(window.ActiveXObject)?{?
//
?IE
????????????
try
?{
????????????????http_request?
=
?
new
?ActiveXObject(
"
Msxml2.XMLHTTP
"
);
????????????}?
catch
?(e)?{
????????????????
try
?{
????????????????????http_request?
=
?
new
?ActiveXObject(
"
Microsoft.XMLHTTP
"
);
????????????????}?
catch
?(e)?{}
????????????}
????????}
????????
if
?(
!
http_request)?{
????????????alert('Giving?up?:(?Cannot?create?an?XMLHTTP?instance');
????????????
return
?
false
;
????????}
????????http_request.onreadystatechange?
=
?alertContents;
????????http_request.open('GET',?url,?
true
);
????????http_request.send(
null
);
????}
????
function
?alertContents()?{
????????
if
?(http_request.readyState?
==
?
4
)?{
????????????
if
?(http_request.status?
==
?
200
)?{
????????????????alert(http_request.responseText);
????????????}?
else
?{
????????????????alert('There?was?a?problem?
with
?the?request.');
????????????}
????????}
????}
</
script
>
<
span
????style
=
"
cursor:?pointer;?text-decoration:?underline
"
????onclick
=
"
makeRequest('test.html')
"
>
????????Make?a?request
</
span
>
在此范例中:
- 首先使用者按下「Make a request」
- 這么一來就會(huì)呼叫
???? makeRequest()
函式,亦傳入?yún)?shù)值 test.html
(也就是那份 HTML 檔的名稱,放在同目錄下)
- 接著發(fā)出 request,而后會(huì)將主導(dǎo)權(quán)交給
???? onreadystatechange
指定的 alertContents()
函式
-
alertContents()
檢查響應(yīng)是否正常,而后以 alert()
將 test.html
的內(nèi)容列出
你可以由此測(cè)試本例 (http://www.w3clubs.com/mozdev/httprequest_test.html),也可以參考測(cè)試檔案 (http://www.w3clubs.com/mozdev/test.html)。
第四步 – 「X 檔案」(又稱為「處理 XML 響應(yīng)值」)
前面的例子中,在收到 HTTP 傳回值后我們以對(duì)象的 reponseText
屬性使用 test.html
檔案的內(nèi)容,接著來試試 responseXML
屬性的方法。
首先,我們得做個(gè)格式正確的 XML 文件,以便稍后取用。此檔名喚 test.xml
,內(nèi)容如下:
<?
xml?version="1.0"?
?>
<
root
>
????I'm?a?test.
</
root
>
在程序中,我們叫用檔案的地方只須略事修改如下:
...
onclick
=
"
makeRequest('test.xml')
"
...
接著在 alertContents()
中,我們必須將 alert(http_request.responseText);
改成這樣:
var
?xmldoc?
=
?http_request.responseXML;
var
?root_node?
=
?xmldoc.getElementsByTagName('root').item(
0
);
alert(root_node.firstChild.data);
這樣一來我們便可取得
responseXML
所傳回的
XMLDocument
對(duì)象,而后以 DOM 相關(guān)的方法取用
XML 文件內(nèi)容。你可以參考
test.xml
的原始碼 (
http://www.w3clubs.com/mozdev/test.xml)
以及修改過后的
測(cè)試程序 (
http://www.w3clubs.com/mozdev/httprequest_test_xml.html)。