Ajax
Ajax技術(shù),即在不需要刷新頁面的情況下從服務(wù)器獲取數(shù)據(jù)進(jìn)行數(shù)據(jù)交互,而實(shí)現(xiàn)Ajax技術(shù)的核心就是使用XHR對象(XMLHttpRequet對象),雖然對象中包含XML,但是在通過Ajax進(jìn)行數(shù)據(jù)交互的時(shí)候并不一定要使用XML格式。
在使用XHR對象創(chuàng)建一個(gè)完整的Ajax請求要使用到open(),send()和readyStatechange事件
open()
open()方法,用于啟動一個(gè)請求以備發(fā)送,接收三個(gè)參數(shù),依次為發(fā)送請求的類型(GET,POST),請求的URL地址,布爾值(是否為異步執(zhí)行).
send()
send()方法,用于執(zhí)行一個(gè)請求并將該請求發(fā)送至服務(wù)器實(shí)現(xiàn)數(shù)據(jù)通信,接收一個(gè)參數(shù),即要發(fā)送給服務(wù)器的數(shù)據(jù),通常為JSON類型的字符串,如果沒有,可以為空或者null,只有當(dāng)調(diào)用了send()方法之后,請求才會發(fā)送給服務(wù)器端。
readyStatechange事件
在數(shù)據(jù)傳輸?shù)倪^程中,我們可以通過status或者readyState屬性來判斷HTTP響應(yīng)的狀態(tài),當(dāng)status的狀態(tài)碼等于200時(shí),代表數(shù)據(jù)已經(jīng)成功傳輸,瀏覽器已經(jīng)接收到了服務(wù)器傳輸?shù)臄?shù)據(jù),此外當(dāng)status的狀態(tài)碼等于304時(shí),表示請求的資源沒有被修改,可以直接調(diào)用緩存中的數(shù)據(jù),也意味著成功響應(yīng)。同時(shí)還可以通過readyState屬性來檢測響應(yīng)的狀態(tài),當(dāng)readyState等于0時(shí),表示未初始化,open()方法未執(zhí)行,1表示啟動,執(zhí)行open()方法,未執(zhí)行send()方法,2表示發(fā)送,成功執(zhí)行send()方法,3表示接收,已經(jīng)接收到一部分的相應(yīng)數(shù)據(jù),4表示完成,接收全部的相應(yīng)數(shù)據(jù),通常在判斷時(shí),當(dāng)readyState等于4時(shí)代表響應(yīng)完全,而readyStatechange事件就是當(dāng)上述兩個(gè)屬性的狀態(tài)改變時(shí)調(diào)用,可以通過該事件來獲取響應(yīng)的數(shù)據(jù)資源,以下為實(shí)例
let xhr = new XMLHttpRequest();
xhr.open("post","http:192.168.43.237:8080/sign",true);
xhr.onreadyStatechange = function(){
if(xhr.readyState == 4){
if(xhr.status>=200 && xhr.status<300 || xhr.status == 304){
console.log(xhr.responseText);
}
}
}
xhr.send(null);
(注意:open()方法中的URL路徑,必須和當(dāng)前頁面所處同一個(gè)域,同一個(gè)端口和協(xié)議,否則就會出現(xiàn)跨域問題導(dǎo)致傳輸被拒絕)
為什么會出現(xiàn)跨域問題
我們在使用Ajax來與服務(wù)器溝通本質(zhì)上是通過XHR(XMLHttpRequest)對象來實(shí)現(xiàn)的,在默認(rèn)情況下,XHR對象只能訪問與包含它的頁面在同一個(gè)域中的資源,換言之,XHR對象只能訪問與包含頁面在同一個(gè)域名,同一個(gè)協(xié)議,同一個(gè)端口中的資源,而這三者中有一種不同,便會判斷為不同域,即產(chǎn)生跨域問題,導(dǎo)致數(shù)據(jù)不能進(jìn)行正常的傳輸。
192.168.43.237:3000/sign | 192.168.43.237:3000/use 同一個(gè)域中
192.168.43.237:3000/sign | 192.168.43.237:8000/use 不同域中
192.168.43.130:3000/sign | 192.168.43.237:3000/use 不同域中
如何解決跨域問題
CORS
CORS(Cross-Origin Resource Sharing 跨域資源共享),是W3C的一個(gè)工作草案,定義了在必須訪問跨域資源時(shí),瀏覽器如何與服務(wù)器進(jìn)行溝通。實(shí)現(xiàn)CORS的核心思想是通過改變HTTP協(xié)議的請求頭內(nèi)容讓瀏覽器與服務(wù)器進(jìn)行溝通,從而決定響應(yīng)或請求是否成功或失敗。
在通過GET或POST向服務(wù)器發(fā)送請求時(shí),瀏覽器會附加一個(gè)Origin頭部,它包含了該請求頁面的源信息(域名,端口號和協(xié)議)
Origin:“http://192.168.43.237:3000”
如果服務(wù)器端同意該請求,就會通過Access-Control-Allow-Origin頭部返回相同的源信息(如果是公共資源,則會返回“*”),如果沒有這個(gè)頭部,或者頭部的源信息不匹配,瀏覽器就會拒絕該請求。
Access-Control-Allow-Origin:“http://192.168.43.237:3000”或
Access-Control-Allow-Origin:“*”
根據(jù)以上規(guī)定,我們就可以通過在服務(wù)器端通過自定義修改Access-Control-Allow-Origin頭部來實(shí)現(xiàn)跨域訪問
允許其他的域進(jìn)行訪問
Access-Control-Allow-Origin:“*”
允許通過get,post請求訪問
Access-Control-Allow-Methods:get,post
設(shè)置響應(yīng)頭
Access-Control-Allow-Headers:Content-type
圖像Ping
圖像Ping是與服務(wù)器進(jìn)行簡單,單項(xiàng)的跨域通信的一種方式,因?yàn)樵诰W(wǎng)頁中,可以通過標(biāo)簽的路徑來獲取任意地方的圖像信息,不存在跨域的問題,通過該方法,請求的數(shù)據(jù)是通過查詢字符串形式發(fā)送的,而響應(yīng)可以是任意內(nèi)容。
function Ping(){
let img = new Image();
var handler = function(event){
switch(event.type){
case "load":
console.log("Done");
break;
case "error":
console.log("Done");
break;
default:
console.log("error");
}
}
img.onload = handler;
img.onerror = handler;
img.src = "http:192.168.43.237:3000/ping?name=xiaohong";
}
該函數(shù)通過事件委托模式為img添加了load和error事件,由于圖片的傳輸不受域的限制,所以服務(wù)器端可以通過get方法接收到img的地址以及地址中包含的參數(shù)name,同時(shí)通過load和error事件可以實(shí)時(shí)了解到用戶點(diǎn)擊事件和圖片加載的次數(shù)
但是通過圖像Ping實(shí)現(xiàn)跨域有兩個(gè)主要的缺點(diǎn),一是只能發(fā)送GET請求,而是無法訪問服務(wù)器的響應(yīng)文本,即單方向的跨域通信,所以對于該方法而言,最主要的用途是用于跟蹤用戶的點(diǎn)擊次數(shù)和廣告的曝光次數(shù)等。
JSONP
JSONP是JSON with padding(參數(shù)式JSON)的簡寫,與圖像Ping實(shí)現(xiàn)跨域的原理有相似,JSONP是通過動態(tài)創(chuàng)建script元素,通過script元素的src來實(shí)現(xiàn)服務(wù)器和瀏覽器之間的跨域訪問,通過參數(shù)式JSON,將回掉函數(shù)變?yōu)閁RL路徑的參數(shù),因?yàn)镴SONP是有效的javascript代碼,所以在服務(wù)器訪問到該路徑是,就會執(zhí)行回掉函數(shù)來處理需要發(fā)送的響應(yīng)數(shù)據(jù)。
下面就是一個(gè)典型的JSONP請求
script.src = "http://192.168.43.237:3000/ping?callback=handler";
以下為一個(gè)簡單的JSONP請求實(shí)例
let btn = document.getElementById("button");
btn.onclick = function(){
let script = document.createElement("script");
script.src = "http://192.168.43.237:3000/ping?callback=handler";
document.body.insertBefore(script, document.body.firstChild);
}
function handler(response){
console.log(responseText);
}
與圖像Ping方法相比,JSONP的優(yōu)勢在于可以獲取到相應(yīng)數(shù)據(jù)文本以及支持在瀏覽器和服務(wù)器之間實(shí)現(xiàn)雙向通信,不過對于JSONP方法而言,不足之處在于只能通過GET請求類型,其次由于JSONP是在其他域中請求數(shù)據(jù),所以如果在相應(yīng)中包含惡意代碼的話,會對Web訪問當(dāng)中的安全因素造成影響。