本文為原創(chuàng)作品。歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明出處:林東洲的博客 | Lindz Blog。
Ajax概念
Ajax全稱為:'Asynchronous Javascript And XML',即異步Javascript和XML,指的是一種創(chuàng)建交互式網(wǎng)頁開發(fā)技術(shù)。
注意,Ajax是一種技術(shù),它并不是一門編程語言。
簡單說來,傳統(tǒng)的網(wǎng)頁如果需要更新內(nèi)容,就必須要重新加載整個頁面。
而通過Ajax在后臺與服務(wù)器進(jìn)行少量的數(shù)據(jù)交換,可以使網(wǎng)頁實現(xiàn)異步更新。這就意味著可以在不重新加載整個網(wǎng)頁的情況下,對網(wǎng)頁的某部分進(jìn)行更新。
例:
比如我在百度上搜索ajax,其實我并沒有點擊‘百度一下‘按鈕進(jìn)行提交表單,但是頁面已經(jīng)向后臺發(fā)起ajax請求獲取數(shù)據(jù),并將獲取到的數(shù)據(jù)在頁面上進(jìn)行局部更新。
Ajax實戰(zhàn)
了解了Ajax的概念之后,接下來就可以學(xué)習(xí)如何發(fā)起Ajax請求了。
在學(xué)習(xí)Ajax之前首先來創(chuàng)建一個form表單:
<form>
<label>Name:<input type='text' id="name" name="name"/></label> <br>
<input type="submit" value="提交" id='submit'>
</form>
<div>Result:<span id="result"></span></div>
表單中有個輸入框和提交按鈕,還有一個用來存儲結(jié)果的div。
效果:
Ajax對象創(chuàng)建
Ajax核心是 Javascript對象 XMLHttpRequest。在創(chuàng)建Ajax對象前需要對所使用的瀏覽器進(jìn)行判斷來創(chuàng)建不同的實例。
var request;
if(window.XMLHttpRequest){
request = new XMLHttpRequest();
}else{
request = new ActiveXObject('Microsoft.XMLHTTP');
}
通過檢測window對象中是否有XMLHttpRequest屬性來確定瀏覽器是否支持標(biāo)準(zhǔn)的XMLHttpRequest。
注意,請不要用瀏覽器的navigator.userAgent來檢測瀏覽器是否支持某個Javascript特性。因為這個字符串可以偽造,而且一般不會采用通過IE的版本判斷Javascript特性。
當(dāng)然也可以使用try catch語句來創(chuàng)建XMLHttpRequest對象。
var request = null;
try{
request = new XMLHttpRequest();
}catch(e){
try{
request = new ActiveXObject('Msxml2.XMLHTTP');
}catch(e){
request = new ActiveXObject('Microsoft.XMLHTTP');
}
}
基本上常用的創(chuàng)建Ajax對象的方式就是這兩種,可以選擇封裝在一個函數(shù)中。
XMLHttp=new XMLHttpRequest()已經(jīng)被大多數(shù)現(xiàn)代標(biāo)準(zhǔn)瀏覽器所支持。
但為了兼容IE瀏覽器,按微軟的方式:XMLHttp=new ActiveXObject("Msxml2.XMLHTTP") 支持IE6+的版本。
如果捕獲錯誤,則嘗試更老的方法:XMLHttp=new ActiveXObject("Microsoft.XMLHTTP") 支持IE5.5+的版本。
設(shè)置回調(diào)函數(shù)
在創(chuàng)建Ajax請求后,要先設(shè)置onreadystatechange回調(diào)函數(shù)(即在請求數(shù)據(jù)返回后進(jìn)行的操作)。在回調(diào)函數(shù)中通常我們只需通過readyState === 4判斷請求是否完成。如果已完成,再根據(jù)status === 200 判斷是否是一個成功的響應(yīng)。
readyState值:(1.2.3.4.5)
- 請求未初始化
- 服務(wù)器連接已建立
- 請求已接收
- 請求處理中
- 請求已完成,且響應(yīng)已就緒
code:
request.onreadystatechange = function () {
if (request.readyState === 4){
if (request.status === 200){
document.getElementById('result').innerHTML = request.responseText;
}
}
}
發(fā)送請求
接下來就是要設(shè)置XMLHttpRequest對象中的open()方法,open()方法一共接受三個參數(shù),第一個參數(shù)指定是GET還是POST,第二個參數(shù)指定URL地址,第三個參數(shù)指定是否使用異步發(fā)送請求,默認(rèn)值是true,所以可以不用填寫。
注意:千萬不要把第三個參數(shù)設(shè)置為false,否則瀏覽器將停止響應(yīng),直到Ajax請求完成,如果這個請求耗時10秒,那么10秒內(nèi)你會發(fā)現(xiàn)瀏覽器處于'假死'狀態(tài)。
最后調(diào)用send()方法才算真正發(fā)送請求,GET請求不需要參數(shù),POST請求需要把body部分以字符串或者FormData對象傳進(jìn)去。
code:
document.getElementById('submit').onclick = function () {
var url = 'index.php?' +'name=' + document.getElementById('name');
request.open('GET',url,true);
request.send();
return false;
}
給提交按鈕綁定一個點擊事件,在點擊的時候?qū)⒄埱髷?shù)據(jù)發(fā)送給后臺,return false避免表單提交。
這樣Ajax請求就完成了,已經(jīng)可以實現(xiàn)不刷新頁面局部刷新。
后臺代碼
這里我使用php來完成實例。
$a[]="Anna";
$a[]="Brittany";
$a[]="Cinderella";
$a[]="Diana";
$a[]="Eva";
$a[]="Fiona";
$a[]="Gunda";
$a[]="Hege";
$a[]="Inga";
$a[]="Johanna";
$a[]="Kitty";
$a[]="Linda";
$a[]="Nina";
$a[]="Ophelia";
$a[]="Petunia";
$a[]="Amanda";
$a[]="Raquel";
$a[]="Cindy";
$a[]="Doris";
$a[]="Eve";
$a[]="Evita";
$a[]="Sunniva";
$a[]="Tove";
$a[]="Unni";
$a[]="Violet";
$a[]="Liza";
$a[]="Elizabeth";
$a[]="Ellen";
$a[]="Wenche";
$a[]="Vicky";
$name = $_GET['name'];
if(strlen($name) > 0){
$result = '';
for($i = 0; $i < count($a); $i++){
if(strtolower($name) == strtolower($a[$i])){
$result = "find the person: $a[$i]";
}
}
}
if($result == ''){
$result = "Can't find the person: $name";
}
echo $result;
這樣前后端就可以跑通了。
測試
安全限制
注意到了上面URL使用的相對路徑,如果將它改成絕對路徑比如:
var url = 'http://127.0.0.1:63342/htdocs/ajax/request.php?name=' + document.getElementById('name').value;
將會報錯,在Chrome的控制臺里,還可以看到錯誤信息。
這是因為瀏覽器的同源策略導(dǎo)致的。默認(rèn)情況下,JavaScript在發(fā)送Ajax請求時,URL的域名必須和當(dāng)前頁面完全一致。
完全一致的意思是,域名要相同(www.example.com和example.com不同),協(xié)議要相同(http和https不同),端口號要相同(默認(rèn)是:80端口,它和:8080就不同)。有的瀏覽器口子松一點,允許端口不同,大多數(shù)瀏覽器都會嚴(yán)格遵守這個限制。
跨域請求方法
一、是通過Flash插件發(fā)送HTTP請求,這種方式可以繞過瀏覽器的安全限制,但必須安裝Flash,并且跟Flash交互。不過Flash用起來麻煩,而且現(xiàn)在用得也越來越少了。
二、是通過在同源域名下架設(shè)一個代理服務(wù)器來轉(zhuǎn)發(fā),JavaScript負(fù)責(zé)把請求發(fā)送到代理服務(wù)器:
'/proxy?url=http:/www.example.com'
代理服務(wù)器再把結(jié)果返回,這樣就遵守了瀏覽器的同源策略。這種方式麻煩之處在于需要服務(wù)器端額外做開發(fā)。
三、JSONP
即JSON with Padding,是JSON的一種“使用模式”,可用于解決主流瀏覽器的跨域數(shù)據(jù)訪問的問題。
它有個限制,只能用GET請求,并且要求返回JavaScript。這種方式跨域?qū)嶋H上是利用了瀏覽器允許跨域引用JavaScript資源。
即Web頁面上調(diào)用Js文件時可以不受跨域限制的影響,不僅如此,凡是擁有'src'這個屬性的標(biāo)簽都擁有跨域的能力,比如:script, img, iframe標(biāo)簽。
代碼如下:
var jsonp = document.createElement('script');
jsonp.type = 'text/javascript';
jsonp.src = 'http://www.example.com/remote.js';
document.getElementsByTagName('head')[0].appendChild(jsonp);
四、CORS
Cross-Origin Resource Sharing 跨域資源共享, CORS是一種允許當(dāng)前域(domain)的資源(比如html/js/web service)被其他域(domain)的腳本請求訪問的機(jī)制。
注:如果瀏覽器支持HTML5,那么就可以一勞永逸地使用新的跨域策略:CORS了。
在了解CORS前,先來搞清楚概念:
Origin表示本域,也就是瀏覽器當(dāng)前頁面的域。當(dāng)JavaScript向外域(如sina.com)發(fā)起請求后,瀏覽器收到響應(yīng)后,首先檢查Access-Control-Allow-Origin是否包含本域,如果是,則此次跨域請求成功,如果不是,則請求失敗,JavaScript將無法獲取到響應(yīng)的任何數(shù)據(jù)。
假設(shè)本域是my.com,外域是sina.com,只要響應(yīng)頭Access-Control-Allow-Origin為http://my.com,或者是*,本次請求就可以成功。
可見,跨域能否成功,取決于對方服務(wù)器是否愿意給你設(shè)置一個正確的Access-Control-Allow-Origin,決定權(quán)始終在對方手中。
服務(wù)器端對于CORS的支持,主要就是通過設(shè)置Access-Control-Allow-Origin來進(jìn)行的,可以添加header頭:
//php
header("Access-Control-Allow-Origin: http://www.example.com");
上面這種跨域請求,稱之為“簡單請求”。簡單請求包括GET、HEAD和POST(POST的Content-Type類型 僅限application/x-www-form-urlencoded、multipart/form-data和text/plain),并且不能出現(xiàn)任何自定義頭(例如,X-Custom: 12345),通常能滿足90%的需求。
注:現(xiàn)代瀏覽器一般都是用JSONP或者CORS來完成跨域請求。
CORS與JSONP相比,更為先進(jìn)、方便和可靠。
- JSONP只能實現(xiàn)GET請求,而CORS支持所有類型的HTTP請求。
- 使用CORS,開發(fā)者可以使用普通的XMLHttpRequest發(fā)起請求和獲得數(shù)據(jù),比起JSONP有更好的錯誤處理。
- JSONP主要被老的瀏覽器支持,它們往往不支持CORS,而絕大多數(shù)現(xiàn)代瀏覽器都已經(jīng)支持了CORS。