AJAX原理及常見面試題
引語
AJAX即AsynchronousJavaScriptAnd XML(非同步JavaScript和XML),是指一種建立互動式網頁應用的網頁開發技術。
AJAX是一種用於建立快速動態網頁的技術。它可以令開發者只向伺服器獲取資料(而不是圖片,html文件等資源),網際網路資源的傳輸變得前所未有的輕量級和純粹,這激發了廣大開發者的創造力,使各式各樣功能強大的網路站點,和網際網路應用如雨後春筍一般冒出,不斷帶給人驚喜。
一、什麼是AJAX
Ajax是一種非同步請求資料的web開發技術,對於改善使用者的體驗和頁面效能很有幫助。簡單地說,在不需要重新重新整理頁面的情況下,Ajax 通過非同步請求載入後臺資料,並在網頁上呈現出來。常見運用場景有表單驗證是否登入成功、百度搜索下拉框提示和快遞單號查詢等等。
Ajax的目的是提高使用者體驗,較少網路資料的傳輸量。同時,由於AJAX請求獲取的是資料而不是html文件,因此它也節省了網路頻寬,讓網際網路使用者的網路衝浪體驗變得更加順暢。
二、AJAX原理是什麼
Ajax相當於在使用者和伺服器之間加了一箇中間層,使使用者操作與伺服器響應非同步化。並不是所有的使用者請求都提交給伺服器,像一些資料驗證和資料處理等都交給Ajax引擎自己來做,只有確定需要從伺服器讀取新資料時再由Ajax引擎代為向伺服器提交請求。
Ajax的原理簡單來說通過XmlHttpRequest物件來向伺服器傳送非同步請求,從伺服器獲得資料,然後用JavaScript來操作DOM而更新頁面。這其中最關鍵的一步就是從伺服器獲得請求資料。要清楚這個過程和原理,我們必須對 XMLHttpRequest有所瞭解。
XMLHttpRequest是ajax的核心機制,它是在IE5中首先引入的,是一種支援非同步請求的技術。簡單的說,也就是JavaScript可以及時向伺服器提出請求和處理響應,而不阻塞使用者。達到無重新整理的效果。
三、AJAX的使用
1. 建立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. 向伺服器傳送請求
xhr.open(method, url, async);
send(string);//`POST`請求時才使用字串引數,否則不用帶引數。
- method:請求的型別;GET或POST
- url:檔案在伺服器上的位置
- async:true(非同步)或 false(同步)
注意:POST請求一定要設定請求頭的格式內容
xhr.open("`POST`", "test.html", true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("fname=Henry&lname=Ford"); //`POST`請求引數放在send裡面,即請求體
一個Promise物件實現的 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. 伺服器響應處理(區分同步跟非同步兩種情況)
responseText獲得字串形式的響應資料。
responseXML獲得XML 形式的響應資料。
同步處理
xhr.open("`GET`","info.txt",false);
xhr.send();
document.`GET`ElementById("mydiv").innerHTML = xhr.responseText; //獲取資料直接顯示在頁面上
非同步處理(推薦)
相對來說比較複雜,要在請求狀態改變事件中處理。
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200){
document.`GET`ElementById("mydiv").innerHTML = xhr.responseText;
}
}
什麼是readyState?
readyState是XMLHttpRequest物件的一個屬性,用來標識當前XMLHttpRequest物件處於什麼狀態。
readyState總共有5個狀態值,分別為0~4,每個值代表了不同的含義:
- 0:未初始化 — 尚未呼叫.open()方法;
- 1:啟動 — 已經呼叫.open()方法,但尚未呼叫.send()方法;
- 2:傳送 — 已經呼叫.send()方法,但尚未接收到響應;
- 3:接收 — 已經接收到部分響應資料;
- 4:完成 — 已經接收到全部響應資料,而且已經可以在客戶端使用了;
什麼是status?
HTTP狀態碼(status)由三個十進位制數字組成,第一個十進位制數字定義了狀態碼的型別,後兩個數字沒有分類的作用。HTTP狀態碼共分為5種類型:
- 1xx(臨時響應):表示臨時響應並需要請求者繼續執行操作的狀態碼。
- 2xx(成功):表示成功處理了請求的狀態碼。
- 3xx(重定向):表示要完成請求,需要進一步操作。通常,這些狀態程式碼用來重定向。
- 4xx(請求錯誤):這些狀態碼錶示請求可能出錯,妨礙了伺服器的處理。
- 5xx(伺服器錯誤):這些狀態碼錶示伺服器在嘗試處理請求時發生內部錯誤。這些錯誤可能是伺服器本身的錯誤,而不是請求出錯。
常見的狀態碼
僅記錄在 RFC2616 上的 HTTP 狀態碼就達 40 種,若再加上 WebDAV(RFC4918、5842)和附加 HTTP 狀態碼 (RFC6585)等擴充套件,數量就達 60 餘種。接下來,我們就介紹一下這些具有代表性的一些狀態碼。
- 200表示從客戶端發來的請求在伺服器端被正常處理了。
- 204表示請求處理成功,但沒有資源返回。
- 301表示永久性重定向。該狀態碼錶示請求的資源已被分配了新的URI,以後應使用資源現在所指的URI。
- 302表示臨時性重定向。
- 304表示客戶端傳送附帶條件的請求時(指採用GET方法的請求報文中包含if-matched,if-modified-since,if-none-match,if-range,if-unmodified-since任一個首部)伺服器端允許請求訪問資源,但因發生請求未滿足條件的情況後,直接返回304Modified(伺服器端資源未改變,可直接使用客戶端未過期的快取)
- 400表示請求報文中存在語法錯誤。當錯誤發生時,需修改請求的內容後再次傳送請求。
- 401表示未授權(Unauthorized),當前請求需要使用者驗證
- 403表示對請求資源的訪問被伺服器拒絕了
- 404表示伺服器上無法找到請求的資源。除此之外,也可以在伺服器端拒絕請求且不想說明理由時使用。
- 500表示伺服器端在執行請求時發生了錯誤。也有可能是Web應用存在的bug或某些臨時的故障。
- 503表示伺服器暫時處於超負載或正在進行停機維護,現在無法處理請求。
4.GET和POST請求資料區別
- GET在瀏覽器回退時是無害的,而POST會再次提交請求。
- GET產生的URL地址可以被Bookmark,而POST不可以。
- GET請求會被瀏覽器主動cache,而POST不會,除非手動設定。
- GET請求只能進行url編碼,而POST支援多種編碼方式。
- GET請求引數會被完整保留在瀏覽器歷史記錄裡,而POST中的引數不會被保留。
- GET請求在URL中傳送的引數是有長度限制的,而POST麼有。
- 對引數的資料型別,GET只接受ASCII字元,而POST沒有限制。
- GET比POST更不安全,因為引數直接暴露在URL上,所以不能用來傳遞敏感資訊。
- GET引數通過URL傳遞,POST放在Request body中。
GET和POST使用場景:
若符合下列任一情況,則推薦用POST方法:
- 請求的結果有持續性的副作用,例如,資料庫內新增新的資料行。
- 若使用GET方法,則表單上收集的資料可能讓URL過長。
- 要傳送的資料不是採用7位的ASCII編碼。
若符合下列任一情況,則推薦用GET方法:
- 請求是為了查詢資源,HTML表單資料僅用來幫助搜尋。
- 請求結果無持續性的副作用。
- 收集的資料及HTML表單內的輸入欄位名稱的總長不超過1024個字元。
資源搜尋網站大全 https://www.renrenfan.com.cn 廣州VI設計公司https://www.houdianzi.com
四、常見AJAX面試題
什麼是AJAX?AJAX作用是什麼?
詳見本文內容=>
原生JavaScript AJAX請求有幾個步驟?分別是什麼?
//建立 XMLHttpRequest 物件
var xhr = new XMLHttpRequest();
//傳送資訊至伺服器時內容編碼型別
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//接受伺服器響應資料
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && (xhr.status == 200) {
// let data = xhr.responseText;
}
};
//規定請求的型別、URL 以及是否非同步處理請求。
xhr.open('GET',url,true);
//傳送請求
xhr.send(null);
JSON字串和JSON物件的相互轉換
//字串轉物件
JSON.parse(json)
eval('(' + jsonstr + ')')
// 物件轉字串
JSON.stringify(json)
AJAX幾種請求方式?他們的優缺點?
詳見本文內容=>
HTTP常見狀態碼有哪些?
詳見本文內容=>
什麼情況造成跨域(什麼是同源策略)?
同源策略是瀏覽器的一個安全功能,不同源的客戶端指令碼在沒有明確授權的情況下,不能讀寫對方資源。所以xyz.com下的js指令碼採用Ajax讀取abc.com裡面的檔案資料是會被拒絕的。
同源策略限制了從同一個源載入的文件或指令碼如何與來自另一個源的資源進行互動。這是一個用於隔離潛在惡意檔案的重要安全機制。
舉個例子:
不受同源策略限制的情況:
- 頁面中的連結,重定向以及表單提交是不會受到同源策略限制的。
- 跨域資源的引入是可以的。但是js不能讀寫載入的內容。如嵌入到頁面中的<script src="..."></script>,<img>,<link>,<iframe>等。
跨域解決方案有哪些?
-
JSONP 只能解決GET跨域(問的最多)
原理:動態建立一個script標籤。利用script標籤的src屬性不受同源策略限制。因為所有的src屬性和href屬性都不受同源策略限制。可以請求第三方伺服器資料內容。
步驟:1. 建立一個script標籤 2. script的src屬性設定介面地址 3. 介面引數,必須要帶一個自定義函式名 要不然後臺無法返回資料。 4. 通過定義函式名去接收後臺返回資料 ```js //去建立一個script標籤 let script = document.createElement("script"); //script的src屬性設定介面地址 並帶一個callback回撥函式名稱 script.src = "http://127.0.0.1:8888/index.php?callback=jsonpCallback"; //插入到頁面 document.head.appendChild(script); //通過定義函式名去接收後臺返回資料 function jsonpCallback(data){ //注意:jsonp返回的資料是json物件可以直接使用 //ajax 取得資料是json字串需要轉換成json物件才可以使用。 } ```
-
CORS:跨域資源共享
原理:伺服器設定Access-Control-Allow-OriginHTTP響應頭之後,瀏覽器將會允許跨域請求
限制:瀏覽器需要支援HTML5,可以支援POST,PUT等方法相容ie9以上
需要後臺設定Access-Control-Allow-Origin: * //允許所有域名訪問,或者 Access-Control-Allow-Origin: http://a.com //只允許所有域名訪問
-
設定 document.domain
原理:相同主域名不同子域名下的頁面,可以設定document.domain讓它們同域
限制:同域document提供的是頁面間的互操作,需要載入iframe頁面// URL http://a.com/foo var ifr = document.createElement('iframe'); ifr.src = 'http://b.a.com/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()方法允許來自不同源的指令碼採用非同步方式進行有限的通訊,可以實現跨文字檔、多視窗、跨域訊息傳遞.
語法:postMessage(data,origin)
- 用Apache做轉發(逆向代理),讓跨域變成同域
五、結語
其實通過XMLHttpRequest或者封裝後的框架進行網路請求,這種方式已經有點老舊了,配置和呼叫方式非常混亂,近幾年剛剛出來的Fetch提供了一個更好的替代方法,它不僅提供了一種簡單,合乎邏輯的方式來跨網路非同步獲取資源,而且可以很容易地被其他技術使用。