Ajax高級(jí)筆記 JavaScript高級(jí)程序設(shè)計(jì)筆記
Ajax通信與數(shù)據(jù)格式無(wú)關(guān),從服務(wù)器獲取的數(shù)據(jù)不一定是XML數(shù)據(jù)。
Ajax的核心:XMLHttpRequest對(duì)象(簡(jiǎn)稱XHR)
在XHR對(duì)象之前,Ajax通信通常使用hack手段,如使用隱藏的或內(nèi)嵌的框架。
XHR對(duì)象為向服務(wù)器發(fā)送信息和解析服務(wù)器響應(yīng)提供了流暢的接口。
1.XMLHttpRequest對(duì)象
IE5是第一款引進(jìn)XHR對(duì)象的瀏覽器,通過(guò)MSXML庫(kù)中的ActiveX對(duì)象實(shí)現(xiàn)(有3個(gè)版本)。
兼容所有瀏覽器,創(chuàng)建XHR對(duì)象:
function createXHR(){ if (typeof XMLHttpRequest != "undefined"){ return new XMLHttpRequest(); } else if (typeof ActiveXObject != "undefined"){ if (typeof arguments.callee.activeXString != "string"){ var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"], i, len; for (i=0,len=versions.length; i < len; i++){ try { new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; break; } catch (ex){ //skip } } } return new ActiveXObject(arguments.callee.activeXString); } else { throw new Error("No XHR object available."); } }
之后就能在所有瀏覽器創(chuàng)建XHR對(duì)象:var xhr = createrXHR();
2.原生XHR對(duì)象 (支持的瀏覽器: IE7+、FF、Chrome、Opera、Safari)
通過(guò)XMLHttpRequest構(gòu)建函數(shù),創(chuàng)建XHR對(duì)象:
var xhr = new XMLHttpRequest();
3.XHR用法
3-1.open()
open() 3個(gè)參數(shù): 發(fā)送的類型、請(qǐng)求的URL、表是否異步的布爾值
xhr.open("get","example.php", false);
①URl為相對(duì)于執(zhí)行代碼的當(dāng)前頁(yè),或絕對(duì)地址;
②false為同步,JavaScript代碼會(huì)在服務(wù)器響應(yīng)后再繼續(xù)執(zhí)行;
③調(diào)用open()只是啟動(dòng)一個(gè)請(qǐng)求以備發(fā)送,還沒(méi)真正發(fā)送;
④只能在同個(gè)域中使用相同端口和協(xié)議的URL發(fā)送請(qǐng)求。
3-2.send()
send() 1個(gè)參數(shù): 請(qǐng)求主體發(fā)送的數(shù)據(jù),不需要通過(guò)請(qǐng)求主體發(fā)送數(shù)據(jù)則傳入null。
調(diào)用send()后,請(qǐng)求被分派到服務(wù)器。
xhr.open("get","example.php", false) ; xhr.send(null);
3-3. 收到響應(yīng)后,響應(yīng)數(shù)據(jù)會(huì)自動(dòng)填充XHR對(duì)象的屬性:
responseText:作為響應(yīng)的主體被返回的文本;
responseXML:若響應(yīng)的內(nèi)容類型”text/xml”或”application/xml”,此屬性保存響應(yīng)數(shù)據(jù)XML DOM文檔
status:響應(yīng)的HTTP狀態(tài);
statusText:HTTP狀態(tài)的說(shuō)明。
☆:無(wú)論什么內(nèi)容類型,響應(yīng)主體的內(nèi)容都會(huì)保存在responseText屬性中。對(duì)于非XML數(shù)據(jù),responseXML屬性值為null。
3-4.status屬性確認(rèn)響應(yīng)是否成功返回
HTTP狀態(tài)代碼:
200:響應(yīng)有效,responseText屬性已就緒,內(nèi)容類型正確下的responseXML也可訪問(wèn)。
304:響應(yīng)有效,只是請(qǐng)求的資源并為修改,可直接使用瀏覽器中緩存的版本。
正確檢查上述2種狀態(tài)代碼:
status判斷
if ((xhr.status >= 200 && xhr.status <=300) || xhr.status == 304) { alert(xhr.responseText); } else { alert("Request was unsuccessful:" + xhr.status); };
3-5.readystate屬性
該屬性存儲(chǔ) 請(qǐng)求/響應(yīng)過(guò)程的 當(dāng)前活動(dòng)狀態(tài)。
0 : 未初始化,未調(diào)用open();
1 : 啟動(dòng),調(diào)用了open();
2 : 發(fā)送,調(diào)用了send(),未接受響應(yīng);
3 : 接受,已接受部分響應(yīng);
4 : 完成,已接受全部響應(yīng),且可在客戶端使用。
3-6.readystatechange事件
該事件,在readystate屬性值改變時(shí)觸發(fā)。
readystatechange事件句柄
var xhr = createXHR(); xhr.onreadystatechange = function(event){ if (xhr.readyState == 4){ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.responseText); } else { alert("Request was unsuccessful: " + xhr.status); } } }; xhr.open("get", "example.txt", true); xhr.send(null);
①必須在調(diào)用open()之前知道readystatechange事件的事件處理程序,確保兼容。
②該事件處理程序中沒(méi)有傳遞event對(duì)象,必須通過(guò)XHR對(duì)象本地來(lái)確定下一步怎么做;
③使用xhr對(duì)象而不使用this對(duì)象,是因?yàn)閛nreadystatechange事件處理程序的作用域問(wèn)題。使用this對(duì)象在一些瀏覽器會(huì)導(dǎo)致函數(shù)執(zhí)行失敗或發(fā)生錯(cuò)誤。
3-7.abort()
調(diào)用此方法可取消異步請(qǐng)求:xhr.abort();
調(diào)用后,xhr對(duì)象停止觸發(fā)事件,不允許訪問(wèn)如何與響應(yīng)相關(guān)的屬性;
終止請(qǐng)求后,應(yīng)對(duì)XHR對(duì)象進(jìn)行解引用操作,不建議重用XHR對(duì)象。
4、HTTP頭部信息
發(fā)送請(qǐng)求時(shí)的頭部信息:
Accept:瀏覽器能夠處理的內(nèi)容類型
Accept-Charset:瀏覽器能夠顯示的字符集
Accept-Encoding:瀏覽器能夠處理的壓縮編碼
Axxept-Language:瀏覽器當(dāng)前設(shè)置的語(yǔ)言
Connection:瀏覽器與服務(wù)器之間連接的類型
Cookie:當(dāng)前頁(yè)面設(shè)置的如何Cookie
Host:發(fā)送請(qǐng)求耳洞頁(yè)面所在域
Referer:發(fā)出請(qǐng)求的頁(yè)面的URI
User-Agent:瀏覽器的用戶代理字符串
setRequestHeader()
設(shè)置自定義頭部信息。
2個(gè)參數(shù):頭部字段名稱、頭部信息值。
需在open()方法之后調(diào)用send()之前調(diào)用setRequestHeader(),才能成功發(fā)送請(qǐng)求頭部信息。
自定義HTTP頭部信息
var xhr = createXHR(); xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.responseText); } else { alert("Request was unsuccessful: " + xhr.status); } } }; xhr.open("get", "example.php", true); xhr.setRequestHeader("MyHeader", "MyValue"); xhr.send(null);
getRequestHeader()
獲取指定的相應(yīng)頭部信息
xhr.getRequestHeader(“MyHeader”); getAllRequestHeader()
獲取一個(gè)包含所有頭部信息的長(zhǎng)字符串
xhr.getAllRequestHeader();
5、GET請(qǐng)求
對(duì)于XHR對(duì)象,位于opne()的URL末尾的查詢字符串 需經(jīng)過(guò)編碼,使用encodeURIComponent()編碼。
名-值對(duì)需用和號(hào)(&)分隔。
自定義函數(shù),添加URL查詢字符串參數(shù):
function addURLParam(url,name,value){ url += (url.indexOf('?') == -1?'?':'&'); url += encodeURIComponent(name) + '=' + encodeURIComponent(value); return url; }
6、POST請(qǐng)求
長(zhǎng)用于想服務(wù)器發(fā)送要保存的數(shù)據(jù)。
由于XHR其初的設(shè)計(jì)是為了處理XML,故在send(0中可傳入XHR DOM文檔。
6-1.服務(wù)端讀取POST數(shù)據(jù)
?、倌J(rèn)情況下,服務(wù)器對(duì)POST請(qǐng)求和提交Web表單不會(huì)一視同仁,故服務(wù)端需要程序來(lái)讀取發(fā)送的原始數(shù)據(jù),并解析出有用部分。
?、赬HR模擬表單提交:
1.將Content-Type頭部信息設(shè)置為application/x-www-form-urlencoded (即表單提交時(shí)的內(nèi)容問(wèn)題);
2.以適當(dāng)格式創(chuàng)建一個(gè)字符串。(通過(guò)serialize()函數(shù)創(chuàng)建該字符串,序列化表單數(shù)據(jù))
XHR模擬表單提交
function submitData(){ var xhr = createXHR(); xhr.onreadystatechange = function(event){ if (xhr.readyState == 4){ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.responseText); } else { alert("Request was unsuccessful: " + xhr.status); } } }; xhr.open("post", "postexample.php", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); var form = document.getElementById("user-info"); xhr.send(serialize(form)); }
7、CORS 跨源資源共享(IE8+、FF、Chrome....)
跨域安全策略限制了Ajax的異步通信,CORS則是定義了跨域時(shí),客戶端和服務(wù)器的溝通。
CORS思想:使用自定義HTTP頭部讓瀏覽器與服務(wù)器進(jìn)行溝通,從而決定請(qǐng)求/響應(yīng)的成功與否。
7-1.給一個(gè)請(qǐng)求附加Origin頭部,包含請(qǐng)求頁(yè)面的源信息(協(xié)議、域名 和 端口)
Origin: http://www.domain.com
服務(wù)器根據(jù)Origin判斷是否接收請(qǐng)求,接收則在Access-Control-Allow-Origin頭部會(huì)發(fā)相同信息。
?。ㄈ羰枪操Y源,可以回發(fā)"*")
Access-Control-Allow-Origin: http://www.domain.com
若無(wú)此頭部或頭部信息不匹配,瀏覽器將駁回請(qǐng)求。
☆請(qǐng)求和響應(yīng)不會(huì)包含cookie信息。
7-2.IE8+對(duì)CORS的實(shí)現(xiàn)
IE8引入的XDR(XDomainRequest)類型,類型XHR,可實(shí)現(xiàn)安全可靠的跨域通信。
7-2-1.XDR與XHR的不同之處:
?、賑ookie不會(huì)隨請(qǐng)求發(fā)送,也不會(huì)隨響應(yīng)返回;
?、谥荒茉O(shè)置請(qǐng)求頭部信息中的Content-Type字段;
?、鄄荒茉L問(wèn)響應(yīng)頭部信息;
?、苤恢С諫ET和POST請(qǐng)求
XDR緩解了CSRF(跨站請(qǐng)求偽造)和XSS(跨站點(diǎn)腳本)問(wèn)題
被請(qǐng)求的資源可判斷用戶代理、來(lái)源頁(yè)面等如何數(shù)據(jù) 來(lái)決定是否設(shè)置Access-Control-Allow-Origin頭部
7-2-2. XDR使用方法類似XHR,創(chuàng)建一個(gè)XDomainRequest實(shí)例,調(diào)用open(),再調(diào)用send()。
XDR只能執(zhí)行異步請(qǐng)求,所以open()方法只有兩個(gè)參數(shù),請(qǐng)求的類型和URL。
在收到響應(yīng)后,只能訪問(wèn)響應(yīng)的原始文本,無(wú)法確定響應(yīng)的狀態(tài)代碼。
只要響應(yīng)有效就會(huì)觸發(fā)load事件,響應(yīng)的數(shù)據(jù)會(huì)保存在responseText屬性中。
如果失?。ㄈ?,響應(yīng)中缺少Access-Control-Allow-Origin頭部)就會(huì)觸發(fā)error事件,但該事件無(wú)有用信息,需要自定義一個(gè)onerror事件句柄。
obload事件-onerror事件
var xdr = new XDomainRequest(); xdr.onload = function(){ alert(xdr.responseText); }; xdr.onerror = function(){ alert("Error!"); }; xdr.open("get", "http://www.somewhere-else.com/xdr.php"); xdr.send(null);
在請(qǐng)求返回前調(diào)用abort()可終止請(qǐng)求。
7-2-3.XDR也支持timeout屬性及ontiomout事件處理程序,在運(yùn)行超過(guò)timeout設(shè)定的秒數(shù)后,調(diào)用ontimeout事件句柄。
為支持POST請(qǐng)求,XDR提供了contentType屬性,用于表示發(fā)送數(shù)據(jù)的格式。
contentType屬性是XDR對(duì)象影響頭部信息的唯一方式。
xdr.contentType = "application/x-www-form-urlencoded";
7-3其他瀏覽器對(duì)CORS的實(shí)現(xiàn)
FF等瀏覽器都通過(guò)XMLHttpRequest對(duì)象實(shí)現(xiàn)了對(duì)CORS的原生支持。要請(qǐng)求另一個(gè)域中的資源時(shí),使用標(biāo)準(zhǔn)XHR對(duì)象并在open()中傳入絕對(duì)URL即可。
標(biāo)準(zhǔn)XHR的跨域
var xhr = createXHR(); xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ alert(xhr.responseText); } else { alert("Request was unsuccessful: " + xhr.status); } } }; xhr.open("get", "http://www.abc.com/page/", true); xhr.send(null);
與IE不同,通過(guò)跨域XHR對(duì)象可以訪問(wèn)status屬性和statusText屬性,也可同步請(qǐng)求。
7-3-1.跨域XHR的限制:
?、俨荒苁褂胹etRequestHeader()設(shè)置自定義頭部;
②不能發(fā)送和接收cookie;
?、壅{(diào)用getAllResponseHeader()方法總會(huì)返回空字符串。
7-3-2.無(wú)論同源請(qǐng)求還是跨域請(qǐng)求都是使用相同的接口,故對(duì)于本地資源,最好用相對(duì)URL,對(duì)遠(yuǎn)程資源再用絕對(duì)URL。
這樣能消除歧義,避免出現(xiàn)限制訪問(wèn)頭部或本地cookie信息等問(wèn)題。
7-4、跨瀏覽器的CORS(IE8+、FF等)
檢測(cè)XHR是否支持CORS的方法:檢查是否存在withCredentials屬性,在結(jié)合檢測(cè)XDomainRequest對(duì)象是否存在。
CORS跨域兼容
function createCORSRequest(method, url){ var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr){ xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined"){ xhr = new XDomainRequest(); xhr.open(method, url); } else { xhr = null; } return xhr; } var request = createCORSRequest("get", "http://www.somewhere-else.com/xdr.php"); if (request){ request.onload = function(){ //do something with request.responseText }; request.send(); }
上述createCORSRequest()函數(shù)返回的對(duì)象的屬性(XHR和XDR的共同屬性):
?、賏bort():停止正在進(jìn)行的請(qǐng)求;
?、趏nerror:用于替代onreadystatechange檢測(cè)錯(cuò)誤;
?、踥nload:用于代替onreadystatechange檢測(cè)成功;
?、躵esponseText:用于取得響應(yīng)內(nèi)容;
?、輘end():用于發(fā)送請(qǐng)求。
8、其他跨域技術(shù)
在CORS出現(xiàn)前,常利用DOM中能夠執(zhí)行跨域請(qǐng)求的功能,在不依賴XHR對(duì)象時(shí),也能發(fā)送某種請(qǐng)求。
與COSR不同的是,不用修改服務(wù)器代碼。
8-1.圖像Ping
使用<img>標(biāo)簽,由于可以從任何網(wǎng)頁(yè)加載圖像,故常是在線廣告跟蹤瀏覽量的只要方式。
可動(dòng)態(tài)創(chuàng)建圖像,使用它們的onload和onerror事件句柄,確定是否接受到了響應(yīng)。
var img = new Image(); img.onload = img.onerror = function(){ alert("Done!"); }; img.src = "http://www.example.com/test?name=Nicholas";
圖像Ping是與服務(wù)器進(jìn)行簡(jiǎn)單、單向的跨域通信的一種方式。請(qǐng)求的數(shù)據(jù)通過(guò)查詢字符串形式發(fā)送,響應(yīng)可以是任何內(nèi)容,通常是像素圖或204響應(yīng)。雖然通過(guò)圖像Ping,瀏覽器得不到任何具體數(shù)據(jù),但通過(guò)偵聽load和error事件,能找到響應(yīng)收到的時(shí)間。
圖像Ping常用于跟蹤用戶點(diǎn)擊頁(yè)面 或動(dòng)態(tài)廣告曝光次數(shù)。
缺點(diǎn):①只能發(fā)送GET請(qǐng)求;②無(wú)法訪問(wèn)服務(wù)器響應(yīng)文本。
8-2.JSONP
JSONP(JSON width Padding)填充式JSON或參數(shù)式JSON,類似JSON,是包含在函數(shù)調(diào)用中的JSON:
callback( {"name" : "value"} );
8-2-1.JSONP有兩個(gè)部分:回調(diào)函數(shù) 和 數(shù)據(jù)
回調(diào)函數(shù):當(dāng)響應(yīng)到來(lái)時(shí)應(yīng)該在頁(yè)面中調(diào)用的函數(shù)?;卣{(diào)函數(shù)的名稱在請(qǐng)求中指定。
數(shù)據(jù):傳入回調(diào)函數(shù)的JSON數(shù)據(jù)。
8-2-2.JSONP通過(guò)動(dòng)態(tài)<script>元素,為其src屬性指定一個(gè)跨域的URL。類似<img>元素,即都能不受限制地跨域加載資源。
JSONP為有效的JavaScript代碼,在請(qǐng)求完成即JSONP響應(yīng) 加載到頁(yè)面后就會(huì)立即執(zhí)行。
function handleResponse(response){ alert("You're at IP address " + response.ip + ", which is in " + response.city + ", " + response.region_name); } var script = document.createElement("script"); script.src = "http://freegeoip.net/json/?callback=handleResponse"; document.body.insertBefore(script, document.body.firstChild);
headleResponse()為回調(diào)函數(shù),將在響應(yīng)到來(lái)后執(zhí)行。
8-2-3.JSONP之所以流行,是因?yàn)?:
?、倌軌蛑苯釉L問(wèn)響應(yīng)文本;
②支持瀏覽器與服務(wù)器之間的雙向通信。
不足:
①JSONP從其他域加載代碼執(zhí)行,因此該域必須安全可靠;
?、诤茈y確保JSONP請(qǐng)求是否失敗。
8-3Comet ”服務(wù)器推送" 【不兼容IE】
Ajax從頁(yè)面想服務(wù)器請(qǐng)求數(shù)據(jù),Comet則是服務(wù)器向頁(yè)面推送數(shù)據(jù),Comet能近乎實(shí)時(shí)地向頁(yè)面推送信息。
8-3-1.實(shí)現(xiàn)Comet的2種方式:長(zhǎng)輪詢 和 流
?、匍L(zhǎng)輪詢:與短輪詢相反,頁(yè)面發(fā)送一個(gè)請(qǐng)求,服務(wù)器一直保持連接打開,直到有數(shù)據(jù)可發(fā)送時(shí)就向頁(yè)面發(fā)送數(shù)據(jù)。接收完數(shù)據(jù)后瀏覽器關(guān)閉連接,隨機(jī)又發(fā)送一個(gè)新請(qǐng)求,在頁(yè)面打開期間如此循環(huán)...
【短輪詢是服務(wù)器立即發(fā)送數(shù)據(jù),即使數(shù)據(jù)無(wú)效,長(zhǎng)輪詢是等待發(fā)送響應(yīng)?!?/p>
輪詢的優(yōu)點(diǎn)是,所有瀏覽器都支持。通過(guò)XHR對(duì)象和setTimeout()實(shí)現(xiàn)。
?、贖TTP流:它在網(wǎng)頁(yè)的整個(gè)生命周期內(nèi)只使用一個(gè)HTTP連接。瀏覽器發(fā)送一個(gè)請(qǐng)求,服務(wù)器保持連接打開,再周期性向?yàn)g覽器發(fā)送數(shù)據(jù).
PHP例子
<?php $i = 0; while (true) { //輸出一些數(shù)據(jù),然后刷新輸出緩存 echo "Number is $1"; flush(); //等幾秒 sleep(10); $++; } ...
實(shí)現(xiàn)HTTP流的關(guān)鍵:所有服務(wù)器端語(yǔ)言都支持打印到輸出緩存然后刷新的功能。(將輸出緩存中的內(nèi)容一次性全部發(fā)送給客戶端)
使用XHR實(shí)現(xiàn)HTTP流的典型例子
var xhr = new XMLHttpRequest(), received = 0; xhr.open("get", url, true); xhr.onreadystatechange = function(){ var result; if (xhr.readyState == 3){ //get only the new data and adjust counter result = xhr.responseText.substring(received); received += result.length; //call the progress callback progress(result); } else if (xhr.readyState == 4){ finished(xhr.responseText); } }; xhr.send(null); return xhr; } var client = createStreamingClient("streaming.php", function(data){ alert("Received: " + data); }, function(data){ alert("Done!"); });
以上就是腳本之家小編為大家分享的Ajax高級(jí)筆記的相關(guān)內(nèi)容,對(duì)于學(xué)習(xí)ajax的朋友應(yīng)該是個(gè)不錯(cuò)的入門講解。
相關(guān)文章
事件綁定之小測(cè)試 onclick && addEventListener
昨晚回去后,和雷子討論如何才能“檢測(cè)”到頁(yè)面上某個(gè)元素都綁定了哪些事件監(jiān)聽函數(shù),第一感覺(jué)就是應(yīng)該從瀏覽器入手,比如FF,或者Chrome等2011-07-07JavaScript大數(shù)相加相乘的實(shí)現(xiàn)方法實(shí)例
這篇文章主要給大家介紹了關(guān)于JavaScript大數(shù)相加相乘的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10javascript對(duì)象的property和prototype是這樣一種關(guān)系
javascript對(duì)象的property和prototype是這樣一種關(guān)系...2007-03-03原生javascript實(shí)現(xiàn)圖片放大鏡效果
這篇文章主要為大家詳細(xì)介紹了原生javascript實(shí)現(xiàn)圖片放大鏡效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01浮動(dòng)的div自適應(yīng)居中顯示的js代碼
這篇文章主要介紹了浮動(dòng)的div自適應(yīng)居中顯示的js代碼,有需要的朋友可以參考一下2013-12-12JavaScript使用Proxy編寫一個(gè)取值限制器
最近一直在開發(fā)低代碼平臺(tái)的東西,由于項(xiàng)目里面東西有點(diǎn)多,取值或調(diào)用起來(lái)比較麻煩,使用本文就將使用Proxy編寫一個(gè)取值限制器,需要的小伙伴可以參考下2023-12-12javascript計(jì)算星座屬相(十二生肖屬相)示例代碼
本文介紹了使用javascript計(jì)算星座和屬相的示例,這個(gè)可以用在用戶注冊(cè)的時(shí)候顯示出來(lái),大家參考使用吧2014-01-01微信小程序 scroll-view 水平滾動(dòng)實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了微信小程序 scroll-view 水平滾動(dòng)實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10