Ajax技術出現的意義:javascript
向服務器請求額外的數據而無序卸載頁面,帶來更好的用戶體驗,頁面無刷新技術。php
以下兼容處理,建立XHR對象 function createXhr(){ if(typeof XMLHttpRequest != undefined){ return new XMLHttpRequest();//使用XMLHttpRequest構造函數來建立XHR對象,適用於IE7及以上版本,若是兼容到IE7,下邊就能夠省略了。 }else if(typeof ActiveXObject != undefined){ //適合IE7以前的版本 if(typeof arguments.callee.activeXString != "string"){ var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML.XMLHttp"]; for(var i = 0,len=versions.length;i<len;i++){ try{ var xhr = new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; return xhr; }catch (ex){ //跳過 } } } return new ActiveXObject(arguments.callee.activeXString); }else{ throw new Error("No XHR object available."); }; } var xhr = new createXhr(); xhr;
結果以下:前端
//客戶端:啓動一個請求,以備發送 xhr.open("get","example.php",false);
傳入三個參數:
第一個參數:請求的方法,get||post||delete;
第二個參數:請求的地址,相對與當前頁面的路徑;
第三個參數:是否異步?true表示異步||false 表示同步,通常狀況下都是選擇異步。java
//客戶端:發送請求 xhr.send(null);
接收一個參數,做爲請求的主體發送的數據(序列化後的data)。若是不須要傳數據就必須傳入 null。jquery
調用send()以後,請求就會被分派到服務器。web
服務器響應的數據會自動填充XHR對象的屬性,相關的屬性簡介以下:ajax
responseText:做爲相應主體被返回的文本。
responseXML:若是響應的數據的內容類型是text/xml或者application/xml,那麼這個屬性就會保存響應數據的XML DOM文檔。
status:響應的HTTP狀態。
statusText:HTTP狀態的說明。json
在客戶端接受到服務器的響應以後:跨域
首先要檢查status屬性,以肯定響應是否已經成功的返回了。promise
狀態碼200:HTTP請求成功,此時responseText屬性內容已就緒,(在內容類型正確的狀況下,responseXML也是能夠訪問的了)。
狀態碼304:請求的內容在服務器端沒有改變,能夠直接使用瀏覽器端的緩存的版本,固然請求也是成功的。
正確的處理響應的函數以下:這裏是同步發送時的處理(函數順序執行),直接經過status來進行判斷是否成功
var xhr = new createXhr(); xhr.open("get","example.php",false);//同步發送,須要等到接收成功以後js才能繼續向下執行。 xhr .send(null); if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ console.log(xhr.responseText); } else { console.log("Request was unsuccessful:" + xhr.status); }
響應的主題都會保存到responseText屬性中,而對於非XML數據,responseXML屬性的值將爲 null。
對於異步發送的請求(true),能夠經過檢測XHR對象的readyState屬性,該屬性表示響應活動的當前活動階段。
該屬性有以下的取值:
0:未初始化。還沒有調用open()方法。
1:啓動。調用了open(),可是沒有調用send()。
2:發送。已經調用了send()方法,可是尚未接收到響應。
3:接收。接受到部分響應。
4:完成。接收到了所有的響應。
在請求狀態改變的時候會觸發readystatechange事件,能夠利用這個事件來檢測每次狀態變化後的readyState的值,這樣就能夠在響應完成的時候肯定響應是否成功,並進行接下來的操做。
注意:爲了保證兼容性,須要在open() 方法以前指定onreadystatechange事件處理程序。
var xhr = new createXhr(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){ console.log(xhr.responseText); } else { console.log("Request was unsuccessful:" + xhr.status); } } } xhr.open("get","example.php",true);//異步發送,發送請求以後,保留狀態監聽事件,繼續執行後邊的操做,若是響應成功,4&&200||304就會執行處理函數。 xhr .send(null);
在接受到相應以前還能夠調用: xhr.abort();方法來取消異步請求。
頭部信息非爲請求頭部和響應頭部。
默認狀況下,發送XHR請求的時候,默認發送下列頭部信息:
Accept:瀏覽器可以拿來處理的內容類型。
Accept-Charset:瀏覽器可以現實的字符集。
Accept-Encoding:瀏覽器可以處理的壓縮編碼。
Accept-Language:瀏覽器當前設置的語言。
Connection:瀏覽器與服務器之間的鏈接類型。
Cookie:當前頁面設置的任何cookie。
Host:發出請求的頁面所在的域。
referer(將錯就錯,本來應該是referrer:推薦人):發出請求頁面的URI。document.referrer:返回當前文檔的url
User-Agent:瀏覽器的用戶代理字符串。
可使用的方法:
setRequestHeader("MyHeader","Myvalue");設置自定義的請求頭部信息。該方法必須位於open()與send()方法之間調用才能夠,準備發起請求,還未發起。
getRequestHeader("Header");獲取指定名稱的頭部信息。
getAllRequestHeaders();獲取全部的頭部信息的長字符串。
常出現的一個問題就是查詢字符串的個是有問題,全部的名稱和值都須要使用encodeURIComponent() 進行編碼。
以下輔助函數能夠解決在url後邊添加查詢字符串的問題:
function addUrlParam(url,name,value){ url += (url.indexOf("?") == -1 ? "?" : "&"); url += encodeURIComponent(name) + "=" +encodeURIComponent(value); return url; }
使用以下:
var url = "https://www.baidu.com"; url = addUrlParam(url,"name","dadaoshenyi");//"https://www.baidu.com?name=dadaoshenyi"
請求主體是一個相似這樣的字符串:name=sdfds&value1=sdfsdfds&value2=sdfsdf......;裏邊的字符都是通過編碼的。
內置的對象:用於序列化表單以及建立與表單個是相同的數據(用於XHR傳輸)。最終傳遞給send()方法。
var form = document.getElementById("user-info"); xhr.send(new FormData(form));
設定超時時間,在超出時間以後檢測ontimeout事件:
xhr.timeout = 1000;//設定時限爲1s xhr.ontimeout = function(){ console.log("Request did not return in a second"); }
一、loadstart:接受到響應數據的第一個字節的時候觸發。
二、progress:接收響應期間一直觸發。週期性的觸發,也會接受到一個event對象,其target屬性指向XHR對象。
三、error:請求發生錯誤的時候觸發。
四、abort:調用abort()方法的時候觸發。
五、load: 接受到完整的響應的時候觸發。用以替代readystatechange事件,響應接收完畢後觸發load事件。這也就是說沒有再檢查readyState屬性了。onload事件處理程序會接受到一個event對象,其target指向XHR對象的實例。
六、loadend:通訊完成時或者觸發error、abort或load事件後觸發。
背後的原理:使用自定義的HTTP頭部讓瀏覽器與服務器進行溝通,從而決定請求應該是成功仍是失敗。受限發送一個option請求,不發送數據。確承認以跨域再發後續的請求。
跨域安全策略:同域名、同端口號、同協議。
以下:在發送請求的時候,客戶端要添加一個額外的頭部,包含頁面請求的源信息(協議、域名和端口號),
Origin:http://www.changyangzhe.com
若是服務器認爲能夠接收這個請求就會回發一個相同的源信息:
Access-Control-Allow-Origin:http://www.changyangzhe.com
這個時候瀏覽器收到這個信息,就會發送請求,若是不匹配就會駁回請求。
跨瀏覽器的CORS
function createCORSRequest (method,url) { var xhr = createXHR(); if ("withCredentails" 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"); if(request) { request.onload = function (){ //相關代碼 } request.send(); }
原理:網頁能夠從任何地方加載任何圖像。
JSONP:JSON with padding(填充式JSON或參數式JSON)
以下的樣式:callback({"name":"changyangzhe"});這樣的文件保存在遠程的js文件中,數據就是傳入的參數,調用的函數名就是callback。
由兩部分組成:回調函數和數據。
回調函數:用來當響應來到的時候應該在頁面中調用的函數,回調函數的名字通常在請求中指定。
數據:就是傳入回調函數中的JSON數據。
實現思路:
一、前端建立script標籤,設置src,添加到head中;
二、後臺返回一個js變量JSONP,這個JSONP就是請求獲得的JSON數據;
三、回調完成以後刪除script標記。
原理:跨域訪問數據就只有一種可能,那就是在遠程服務器上設法把數據裝進js格式的文件裏,供客戶端調用和進一步處理。
方案:web客戶端經過與調用腳本如出一轍的方式,來調用跨域服務器上動態生成的js格式文件(通常以JSON爲後綴),顯而易見,服務器之因此要動態生成JSON文件,目的就在於把客戶端須要的數據裝入進去。
以下實例:
http://free.net/json/?callback=handleRequest
這裏是在請求一個JSONP的地理定位服務。這裏的回調函數的名字叫handleRequest()。
JSONP是經過動態<script>元素來使用的,使用時能夠爲src指定一個跨域URL,與 <img>相似,能夠不受限制的從其餘域加載資源。
由於JSONP是有效的js代碼,因此在請求完成以後,即在JSONP響應加載到頁面中之後,就會當即執行。
本地文件以下:
function handleRequest(response){ console.log("you are at IP address " + response.ip + ",which is in" + response.city + "," + response.region_name); } var script = document.createElement("script");
//提供jsonp服務的url地址(不論是什麼類型的地址,最終生成的返回值都是一段javascript代碼)
script.src = "http://free.net/json/?callback=handleRequest";//遠程的回調函數名
document.body.insertBefore(script,document.body.firstChild);
遠程的文件:
如romot.js,裏邊的內容如callback("ip":"123456789","city":"hangzhou");
特色:支持雙向的通訊
不足:不能防止其餘域的惡意代碼;判斷JSONP請求成功與否並不容易。
//仍是忍不住吐槽,雖然jquery也把jsonp納入了ajax,但其實它們真的不是一回事兒,jsonp不是ajax的一個特例 //但ajax和jsonp其實本質上是不一樣的東西。ajax的核心是經過XmlHttpRequest獲取非本頁內容,而jsonp的核心則是動態添加<script>標籤來調用服務器提供的js腳本。 //其實ajax與jsonp的區別不在因而否跨域,ajax經過服務端代理同樣能夠實現跨域,jsonp自己也不排斥同域的數據的獲取。 jQuery(document).ready(function(){ $.ajax({ type: "get", async: false, url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998", dataType: "jsonp", jsonp: "callback",//傳遞給請求處理程序或頁面的,用以得到jsonp回調函數名的參數名(通常默認爲:callback) jsonpCallback:"flightHandler",//自定義的jsonp回調函數名稱,默認爲jQuery自動生成的隨機函數名,也能夠寫"?",jQuery會自動爲你處理數據 success: function(json){//自動幫你生成回調函數並把數據取出來供success屬性方法來調用,是否是很爽呀,也就不用動態生成標籤了 alert('您查詢到航班信息:票價: ' + json.price + ' 元,餘票: ' + json.tickets + ' 張。'); }, error: function(){ alert('fail'); } }); }); //請求的頁面生成以下一段代碼,這是服務端要生成的js片斷 flightHandler({ "code": "CA1998", "price": 1780, "tickets": 5 });
有以下幾種區別:
1. Ajax在提交、請求、接收時,都是異步進行的,網頁不須要刷新;Form提交則是新建一個頁面,哪怕是提交給本身自己的頁面,也是須要刷新的;
2. Ajax在提交時,是在後臺新建一個請求;F倒是放棄本頁面,然後再請求;
3. A必需要使用JS來實現,不啓用JS的瀏覽器,沒法完成該操做;F倒是瀏覽器的本能,不管是否開啓JS,均可以提交表單;
4. A在提交、請求、接收時,整個過程都須要使用程序來對其數據進行處理;F提交時,倒是根據你的表單結構自動完成,不須要代碼干預。
典型的jquery,ajax實現,這裏返回的是一個promise對象:
$.ajax({ type: 'GET', async: false, url: 'http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx/getCountryCityByIp?callback=?', data:{theIpAddress:host_ip[0]}, dataType: 'jsonp', jsonp: "callback", success: function(msg){ alert(JSON.stringify(msg)); }, error:function(XMLHttpRequest, textStatus, errorThrown){ alert(XMLHttpRequest.status); alert(XMLHttpRequest.readyState); alert(XMLHttpRequest.responseText); alert(textStatus); alert(errorThrown); console.log(textStatus); } });