什么是Ajax弥雹?
AJAX = Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)。意思就是用JavaScript執(zhí)行異步網(wǎng)絡(luò)請求珍特。
AJAX 不是新的編程語言,而是一種使用現(xiàn)有標(biāo)準(zhǔn)的新方法魔吐。
AJAX 最大的優(yōu)點是在不重新加載整個頁面的情況下,可以與服務(wù)器交換數(shù)據(jù)并更新部分網(wǎng)頁內(nèi)容。
AJAX 不需要任何瀏覽器插件赦颇,但需要用戶允許JavaScript在瀏覽器上執(zhí)行。
如果仔細(xì)觀察一個Form提交奥溺,你就會發(fā)現(xiàn),一旦用戶點擊"submit"按鈕骨宠,表單開始提交浮定,瀏覽器就會開始刷新頁面,然后在新頁面里告訴你操作是成功了還是失敗了层亿,如果不幸由于網(wǎng)絡(luò)太慢或者其他原因桦卒,就會得到一個404頁面。
這就是Web的運作原理匿又,一次HTTP請求方灾,對應(yīng)一個頁面。
如果要讓用戶瀏覽當(dāng)前頁面中碌更,同時發(fā)出新的HTTP請求裕偿,就必須用javascript發(fā)送這個新請求,接收到數(shù)據(jù)后痛单,再用JavaScript更新頁面嘿棘,這樣一來,用戶就感覺自己仍然停留在當(dāng)前頁面旭绒,但數(shù)據(jù)卻不斷的更新鸟妙。
最早大規(guī)模使用Ajax的就是Gmail,Gmail的頁面在首次加載后,剩下的所有數(shù)據(jù)挥吵,都依賴于Ajax來更新重父。
用JavaScript來寫一個完成的Ajax代碼并不復(fù)雜,但是需要注意:Ajax請求是異步執(zhí)行的蔫劣,也就是說坪郭,要通過回調(diào)函數(shù)獲得響應(yīng)个从。
Ajax創(chuàng)建流程
一:創(chuàng)建XMLHttpRequest對象(標(biāo)準(zhǔn)寫法和IE寫法混在一起)
var xhr;
//現(xiàn)代瀏覽器
if(window.XMLHttpRequest){
xhr = new XMLHttpRequset();
}else{
//低版本IE瀏覽器脉幢,需要ActiveXObject
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
二:對xhr進行配置
xhr.open("傳輸方式GET或POST","網(wǎng)址","是否異步");
三:發(fā)送網(wǎng)絡(luò)請求
xhr.send();
四:監(jiān)聽網(wǎng)絡(luò)請求狀態(tài),并接收網(wǎng)絡(luò)返回的數(shù)據(jù)
xhr.onreadystatechange=function(){
if(xhr.readyState===4){ //成功完成
//判斷響應(yīng)結(jié)果
if((xhr.status>=200&&xhr.status<300)||xhr.status===304){
// 成功嗦锐,通過responseText拿到響應(yīng)的文本:
console.log(xhr.responseText);
}else {
// 失敗嫌松,根據(jù)響應(yīng)碼判斷失敗原因:
console.log(xhr.status)
}
}
}
注意:
status存儲的是HTTP狀態(tài)碼,狀態(tài)碼都是服務(wù)器發(fā)過來的,表示的是服務(wù)器狀態(tài)
200 - OK 一切正常奕污,對GET和POST請求的應(yīng)答文檔跟在后面
304 - Not Modified 客戶端有緩沖的文檔并發(fā)出了一個條件性的請求,服務(wù)器告訴客戶萎羔,原來緩沖的文檔還可以繼續(xù)使用。
400 - Bad Request 請求出現(xiàn)語法錯誤碳默。
404 - Not Found 無法找到指定位置的資源贾陷。這也是一個常用的應(yīng)答缘眶。-
XMLHttpRequest.readyState 屬性返回一個 XMLHttpRequest 代理當(dāng)前所處的狀態(tài)。一個 XHR 代理總是處于下列狀態(tài)中的一個:
image.png
注意:
通過檢測window對象是否有XMLHttpRequest屬性來確定瀏覽器是否支持標(biāo)準(zhǔn)的XMLHttpRequest髓废。注意巷懈,不要根據(jù)瀏覽器的navigator.userAgent來檢測瀏覽器是否支持某個JavaScript特性,一是因為這個字符串本身可以偽造慌洪,二是通過IE版本判斷JavaScript特性將非常復(fù)雜顶燕。
當(dāng)創(chuàng)建了XMLHttpRequest對象后,要先設(shè)置onreadystatechange的回調(diào)函數(shù)冈爹。在回調(diào)函數(shù)中涌攻,通常我們只需通過readyState === 4判斷請求是否完成,如果已完成频伤,再根據(jù)status === 200判斷是否是一個成功的響應(yīng)恳谎。
XMLHttpRequest對象的open()方法有3個參數(shù),第一個參數(shù)指定是GET還是POST剂买,第二個參數(shù)指定URL地址惠爽,第三個參數(shù)指定是否使用異步,默認(rèn)是true瞬哼,所以不用寫婚肆。
注意,千萬不要把第三個參數(shù)指定為false坐慰,否則瀏覽器將停止響應(yīng)较性,直到AJAX請求完成。如果這個請求耗時10秒结胀,那么10秒內(nèi)你會發(fā)現(xiàn)瀏覽器處于“假死”狀態(tài)赞咙。
最后調(diào)用send()方法才真正發(fā)送請求。GET請求不需要參數(shù)糟港,POST請求需要把body部分以字符串或者FormData對象傳進去攀操。
安全限制
- 瀏覽器的同源策略,默認(rèn)情況下秸抚,JavaScript在發(fā)送AJAX請求時速和,URL的域名必須和當(dāng)前頁面完全一致。
- 完全一致的意思是剥汤,域名要相同(www.example.com和example.com不同)颠放,協(xié)議要相同(http和https不同),端口號要相同(默認(rèn)是:80端口吭敢,它和:8080就不同)碰凶。有的瀏覽器口子松一點,允許端口不同,大多數(shù)瀏覽器都會嚴(yán)格遵守這個限制欲低。
那是不是用JavaScript無法請求外域(就是其他網(wǎng)站)的URL了呢辕宏?方法還是有的,大概有這么幾種:
一是通過Flash插件發(fā)送HTTP請求砾莱,這種方式可以繞過瀏覽器的安全限制匾效,但必須安裝Flash,并且跟Flash交互恤磷。不過Flash用起來麻煩面哼,而且現(xiàn)在用得也越來越少了。
二是通過在同源域名下架設(shè)一個代理服務(wù)器來轉(zhuǎn)發(fā)扫步,JavaScript負(fù)責(zé)把請求發(fā)送到代理服務(wù)器:
'/proxy?url=http://www.sina.com.cn'
代理服務(wù)器再把結(jié)果返回魔策,這樣就遵守了瀏覽器的同源策略。這種方式麻煩之處在于需要服務(wù)器端額外做開發(fā)河胎。
- 第三種方式稱為JSONP闯袒,它有個限制,只能用GET請求游岳,并且要求返回JavaScript政敢。這種方式跨域?qū)嶋H上是利用了瀏覽器允許跨域引用JavaScript資源:
<html>
<head>
<script src="http://example.com/abc.js"></script>
...
</head>
<body>
...
</body>
</html>
JSONP通常以函數(shù)調(diào)用的形式返回,例如胚迫,返回JavaScript內(nèi)容如下:
foo('data');
這樣一來喷户,我們?nèi)绻陧撁嬷邢葴?zhǔn)備好foo()函數(shù),然后給頁面動態(tài)加一個<script>節(jié)點访锻,相當(dāng)于動態(tài)讀取外域的JavaScript資源褪尝,最后就等著接收回調(diào)了。
以163的股票查詢URL為例期犬,對于URL:http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice河哑,你將得到如下返回:
refreshPrice({"0000001":{"code": "0000001", ... });
因此我們需要首先在頁面中準(zhǔn)備好回調(diào)函數(shù):
function refreshPrice(data) {
var p = document.getElementById('test-jsonp');
p.innerHTML = '當(dāng)前價格:' +
data['0000001'].name +': ' +
data['0000001'].price + ';' +
data['1399001'].name + ': ' +
data['1399001'].price;
}
當(dāng)前價格:上證指數(shù): 2606.91龟虎;深證成指: 7558.277
最后用getPrice()函數(shù)觸發(fā):
function getPrice() {
var
js = document.createElement('script'),
head = document.getElementsByTagName('head')[0];
js.src = 'http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice';
head.appendChild(js);
}
就完成了跨域加載數(shù)據(jù)璃谨。
CORS
如果瀏覽器支持HTML5,那么就可以一勞永逸地使用新的跨域策略:CORS了鲤妥。
CORS全稱Cross-Origin Resource Sharing佳吞,是HTML5規(guī)范定義的如何跨域訪問資源。
了解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)始終在對方手中蛔添。
上面這種跨域請求,稱之為“簡單請求”兜辞。簡單請求包括GET迎瞧、HEAD和POST(POST的Content-Type類型
僅限application/x-www-form-urlencoded、multipart/form-data和text/plain)逸吵,并且不能出現(xiàn)任何自定義頭(例如凶硅,X-Custom: 12345),通常能滿足90%的需求扫皱。
無論你是否需要用JavaScript通過CORS跨域請求資源咏尝,你都要了解CORS的原理。最新的瀏覽器全面支持HTML5啸罢。在引用外域資源時编检,除了JavaScript和CSS外,都要驗證CORS扰才。例如允懂,當(dāng)你引用了某個第三方CDN上的字體文件時:
/* CSS */
@font-face {
font-family: 'FontAwesome';
src: url('http://cdn.com/fonts/fontawesome.ttf') format('truetype');
}
如果該CDN服務(wù)商未正確設(shè)置Access-Control-Allow-Origin,那么瀏覽器無法加載字體資源衩匣。
對于PUT蕾总、DELETE以及其他類型如application/json的POST請求,在發(fā)送AJAX請求之前琅捏,瀏覽器會先發(fā)送一個OPTIONS請求(稱為preflighted請求)到這個URL上生百,詢問目標(biāo)服務(wù)器是否接受:
OPTIONS /path/to/resource HTTP/1.1
Host: bar.com
Origin: http://my.com
Access-Control-Request-Method: POST
服務(wù)器必須響應(yīng)并明確指出允許的Method:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://my.com
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS
Access-Control-Max-Age: 86400
瀏覽器確認(rèn)服務(wù)器響應(yīng)的Access-Control-Allow-Methods頭確實包含將要發(fā)送的AJAX請求的Method,才會繼續(xù)發(fā)送AJAX柄延,否則蚀浆,拋出一個錯誤。