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

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