引語AJAX 即 Asynchronous Javascript And XML (異步JavaScript和XML),是指一種創(chuàng)建交互式網(wǎng)頁應(yīng)用的網(wǎng)頁開發(fā)技術(shù)。
AJAX 是一種用于創(chuàng)建快速動態(tài)網(wǎng)頁的技術(shù)。它可以令開發(fā)者只向服務(wù)器獲取數(shù)據(jù)(而不是圖片,HTML文檔等資源),互聯(lián)網(wǎng)資源的傳輸變得前所未有的輕量級和純粹,這激發(fā)了廣大開發(fā)者的創(chuàng)造力,使各式各樣功能強大的網(wǎng)絡(luò)站點,和互聯(lián)網(wǎng)應(yīng)用如雨后春筍一般冒出,不斷帶給人驚喜。

一、什么是AJAXAjax 是一種異步請求數(shù)據(jù)的web開發(fā)技術(shù),對于改善用戶的體驗和頁面性能很有幫助。簡單地說,在不需要重新刷新頁面的情況下,Ajax 通過異步請求加載后臺數(shù)據(jù),并在網(wǎng)頁上呈現(xiàn)出來。常見運用場景有表單驗證是否登入成功、百度搜索下拉框提示和快遞單號查詢等等。
Ajax的目的是提高用戶體驗,較少網(wǎng)絡(luò)數(shù)據(jù)的傳輸量。同時,由于AJAX請求獲取的是數(shù)據(jù)而不是HTML文檔,因此它也節(jié)省了網(wǎng)絡(luò)帶寬,讓互聯(lián)網(wǎng)用戶的網(wǎng)絡(luò)沖浪體驗變得更加順暢。 二、AJAX原理是什么Ajax相當(dāng)于在用戶和服務(wù)器之間加了一個中間層,使用戶操作與服務(wù)器響應(yīng)異步化。并不是所有的用戶請求都提交給服務(wù)器,像一些數(shù)據(jù)驗證和數(shù)據(jù)處理等都交給Ajax引擎自己來做,只有確定需要從服務(wù)器讀取新數(shù)據(jù)時再由Ajax引擎代為向服務(wù)器提交請求。 Ajax的原理簡單來說通過XmlHttpRequest對象來向服務(wù)器發(fā)送異步請求,從服務(wù)器獲得數(shù)據(jù),然后用JavaScript來操作DOM而更新頁面。這其中最關(guān)鍵的一步就是從服務(wù)器獲得請求數(shù)據(jù)。要清楚這個過程和原理,我們必須對 XMLHttpRequest有所了解。 XMLHttpRequest是ajax的核心機制,它是在IE5中首先引入的,是一種支持異步請求的技術(shù)。簡單的說,也就是JavaScript可以及時向服務(wù)器提出請求和處理響應(yīng),而不阻塞用戶。達(dá)到無刷新的效果。 三、AJAX的使用1. 創(chuàng)建Ajax核心對象XMLHttpRequest (記得考慮兼容性)let xhr = null;
if (window.`XMLHttpRequest`) {// 兼容 IE7+, Firefox, Chrome, Opera, Safari
xhr = new `XMLHttpRequest`();
} else {// 兼容 IE6, IE5
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
2. 向服務(wù)器發(fā)送請求xhr.open(method, url, async);
send(string);//`POST`請求時才使用字符串參數(shù),否則不用帶參數(shù)。
注意:POST 請求一定要設(shè)置請求頭的格式內(nèi)容 xhr.open("`POST`", "test.html", true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("fname=Henry&lname=Ford"); //`POST`請求參數(shù)放在send里面,即請求體
一個Promise對象實現(xiàn)的 Ajax 操作的例子: const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出錯了', error);
});
3. 服務(wù)器響應(yīng)處理(區(qū)分同步跟異步兩種情況)responseText 獲得字符串形式的響應(yīng)數(shù)據(jù)。
responseXML 獲得XML 形式的響應(yīng)數(shù)據(jù)。
同步處理xhr.open("`GET`","info.txt",false);
xhr.send();
document.`GET`ElementById("myDiv").innerHTML = xhr.responseText; //獲取數(shù)據(jù)直接顯示在頁面上
異步處理(推薦)相對來說比較復(fù)雜,要在請求狀態(tài)改變事件中處理。 xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200){
document.`GET`ElementById("myDiv").innerHTML = xhr.responseText;
}
}
什么是readyState ?readyState 是XMLHttpRequest 對象的一個屬性,用來標(biāo)識當(dāng)前XMLHttpRequest 對象處于什么狀態(tài)。 readyState總共有5個狀態(tài)值,分別為0~4,每個值代表了不同的含義:
0 :未初始化 — 尚未調(diào)用.open()方法;
1 :啟動 — 已經(jīng)調(diào)用.open()方法,但尚未調(diào)用.send()方法;
2 :發(fā)送 — 已經(jīng)調(diào)用.send()方法,但尚未接收到響應(yīng);
3 :接收 — 已經(jīng)接收到部分響應(yīng)數(shù)據(jù);
4 :完成 — 已經(jīng)接收到全部響應(yīng)數(shù)據(jù),而且已經(jīng)可以在客戶端使用了;
什么是status ?HTTP狀態(tài)碼(status)由三個十進(jìn)制數(shù)字組成,第一個十進(jìn)制數(shù)字定義了狀態(tài)碼的類型,后兩個數(shù)字沒有分類的作用。HTTP狀態(tài)碼共分為5種類型: 1xx (臨時響應(yīng)):表示臨時響應(yīng)并需要請求者繼續(xù)執(zhí)行操作的狀態(tài)碼。
2xx (成功):表示成功處理了請求的狀態(tài)碼。
3xx (重定向):表示要完成請求,需要進(jìn)一步操作。通常,這些狀態(tài)代碼用來重定向。
4xx (請求錯誤):這些狀態(tài)碼表示請求可能出錯,妨礙了服務(wù)器的處理。
5xx (服務(wù)器錯誤):這些狀態(tài)碼表示服務(wù)器在嘗試處理請求時發(fā)生內(nèi)部錯誤。這些錯誤可能是服務(wù)器本身的錯誤,而不是請求出錯。
常見的狀態(tài)碼僅記錄在 RFC2616 上的 HTTP 狀態(tài)碼就達(dá) 40 種,若再加上 WebDAV(RFC4918、5842)和附加 HTTP 狀態(tài)碼 (RFC6585)等擴(kuò)展,數(shù)量就達(dá) 60 余種。接下來,我們就介紹一下這些具有代表性的一些狀態(tài)碼。 200 表示從客戶端發(fā)來的請求在服務(wù)器端被正常處理了。
204 表示請求處理成功,但沒有資源返回。
301 表示永久性重定向。該狀態(tài)碼表示請求的資源已被分配了新的URI,以后應(yīng)使用資源現(xiàn)在所指的URI。
302 表示臨時性重定向。
304 表示客戶端發(fā)送附帶條件的請求時(指采用GET 方法的請求報文中包含if-matched,if-modified-since,if-none-match,if-range,if-unmodified-since任一個首部)服務(wù)器端允許請求訪問資源,但因發(fā)生請求未滿足條件的情況后,直接返回304Modified(服務(wù)器端資源未改變,可直接使用客戶端未過期的緩存)
400 表示請求報文中存在語法錯誤。當(dāng)錯誤發(fā)生時,需修改請求的內(nèi)容后再次發(fā)送請求。
401 表示未授權(quán)(Unauthorized),當(dāng)前請求需要用戶驗證
403 表示對請求資源的訪問被服務(wù)器拒絕了
404 表示服務(wù)器上無法找到請求的資源。除此之外,也可以在服務(wù)器端拒絕請求且不想說明理由時使用。
500 表示服務(wù)器端在執(zhí)行請求時發(fā)生了錯誤。也有可能是Web應(yīng)用存在的bug或某些臨時的故障。
503 表示服務(wù)器暫時處于超負(fù)載或正在進(jìn)行停機維護(hù),現(xiàn)在無法處理請求。
4. GET 和POST 請求數(shù)據(jù)區(qū)別GET 在瀏覽器回退時是無害的,而POST 會再次提交請求。
GET 產(chǎn)生的URL地址可以被Bookmark,而POST 不可以。
GET 請求會被瀏覽器主動cache,而POST 不會,除非手動設(shè)置。
GET 請求只能進(jìn)行url編碼,而POST 支持多種編碼方式。
GET 請求參數(shù)會被完整保留在瀏覽器歷史記錄里,而POST 中的參數(shù)不會被保留。
GET 請求在URL中傳送的參數(shù)是有長度限制的,而POST 么有。
對參數(shù)的數(shù)據(jù)類型,GET 只接受ASCII字符,而POST 沒有限制。 GET 比POST 更不安全,因為參數(shù)直接暴露在URL上,所以不能用來傳遞敏感信息。
GET 參數(shù)通過URL傳遞,POST 放在Request body中。
GET 和POST 使用場景: 若符合下列任一情況,則推薦用POST 方法:
請求的結(jié)果有持續(xù)性的副作用,例如,數(shù)據(jù)庫內(nèi)添加新的數(shù)據(jù)行。 若使用GET 方法,則表單上收集的數(shù)據(jù)可能讓URL過長。 要傳送的數(shù)據(jù)不是采用7位的ASCII編碼。
若符合下列任一情況,則推薦用GET 方法: 四、常見AJAX面試題什么是AJAX?AJAX作用是什么?詳見本文內(nèi)容=> 原生JavaScript AJAX請求有幾個步驟?分別是什么?//創(chuàng)建 XMLHttpRequest 對象
var xhr = new XMLHttpRequest();
//發(fā)送信息至服務(wù)器時內(nèi)容編碼類型
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//接受服務(wù)器響應(yīng)數(shù)據(jù)
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && (xhr.status == 200) {
// let data = xhr.responseText;
}
};
//規(guī)定請求的類型、URL 以及是否異步處理請求。
xhr.open('GET',url,true);
//發(fā)送請求
xhr.send(null);
JSON字符串和JSON對象的相互轉(zhuǎn)換//字符串轉(zhuǎn)對象
JSON.parse(json)
eval('(' + jsonstr + ')')
// 對象轉(zhuǎn)字符串
JSON.stringify(json)
AJAX幾種請求方式?他們的優(yōu)缺點?詳見本文內(nèi)容=> HTTP常見狀態(tài)碼有哪些?詳見本文內(nèi)容=> 什么情況造成跨域(什么是同源策略)?同源策略是瀏覽器的一個安全功能,不同源的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對方資源。所以xyz.com下的js腳本采用Ajax 讀取abc.com里面的文件數(shù)據(jù)是會被拒絕的。 同源策略限制了從同一個源加載的文檔或腳本如何與來自另一個源的資源進(jìn)行交互。這是一個用于隔離潛在惡意文件的重要安全機制。 舉個例子: 
不受同源策略限制的情況: 頁面中的鏈接,重定向以及表單提交是不會受到同源策略限制的。 跨域資源的引入是可以的。但是js不能讀寫加載的內(nèi)容。如嵌入到頁面中的<script src="..."></script>,<img>,<link>,<iframe>等。
跨域解決方案有哪些?JSONP 只能解決GET跨域(問的最多) 原理:動態(tài)創(chuàng)建一個script標(biāo)簽。利用script標(biāo)簽的src屬性不受同源策略限制。因為所有的src屬性和href屬性都不受同源策略限制??梢哉埱蟮谌椒?wù)器數(shù)據(jù)內(nèi)容。 步驟: 1. 創(chuàng)建一個script標(biāo)簽
2. script的src屬性設(shè)置接口地址
3. 接口參數(shù),必須要帶一個自定義函數(shù)名 要不然后臺無法返回數(shù)據(jù)。
4. 通過定義函數(shù)名去接收后臺返回數(shù)據(jù)
```js
//去創(chuàng)建一個script標(biāo)簽
let script = document.createElement("script");
//script的src屬性設(shè)置接口地址 并帶一個callback回調(diào)函數(shù)名稱
script.src = "http://127.0.0.1:8888/index.php?callback=jsonpCallback";
//插入到頁面
document.head.appendChild(script);
//通過定義函數(shù)名去接收后臺返回數(shù)據(jù)
function jsonpCallback(data){
//注意:jsonp返回的數(shù)據(jù)是json對象可以直接使用
//ajax 取得數(shù)據(jù)是json字符串需要轉(zhuǎn)換成json對象才可以使用。
}
```
CORS:跨域資源共享 原理:服務(wù)器設(shè)置Access-Control-Allow-OriginHTTP 響應(yīng)頭之后,瀏覽器將會允許跨域請求 限制:瀏覽器需要支持HTML5,可以支持POST ,PUT 等方法兼容ie9以上 需要后臺設(shè)置 Access-Control-Allow-Origin: * //允許所有域名訪問,或者
Access-Control-Allow-Origin: http:// //只允許所有域名訪問
設(shè)置 document.domain 原理:相同主域名不同子域名下的頁面,可以設(shè)置document.domain 讓它們同域 限制:同域document提供的是頁面間的互操作,需要載入iframe頁面 // URL http:///foo
var ifr = document.createElement('iframe');
ifr.src = 'http://b./bar';
ifr.onload = function(){
var ifrdoc = ifr.contentDocument || ifr.contentWindow.document;
ifrdoc.getElementsById("foo").innerHTML);
};
ifr.style.display = 'none';
document.body.appendChild(ifr);
ES5 postMessage ES5新增的 postMessage() 方法允許來自不同源的腳本采用異步方式進(jìn)行有限的通信,可以實現(xiàn)跨文本檔、多窗口、跨域消息傳遞. 語法: postMessage(data,origin)
用Apache做轉(zhuǎn)發(fā)(逆向代理),讓跨域變成同域
五、結(jié)語其實通過 XMLHttpRequest 或者封裝后的框架進(jìn)行網(wǎng)絡(luò)請求,這種方式已經(jīng)有點老舊了,配置和調(diào)用方式非?;靵y,近幾年剛剛出來的Fetch提供了一個更好的替代方法,它不僅提供了一種簡單,合乎邏輯的方式來跨網(wǎng)絡(luò)異步獲取資源,而且可以很容易地被其他技術(shù)使用。
|