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

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