AJAX
即 Asynchronous Javascript And XML
(異步JavaScript和XML),是指一種創(chuàng)建交互式網(wǎng)頁(yè)應(yīng)用的網(wǎng)頁(yè)開(kāi)發(fā)技術(shù)。
AJAX
是一種用于創(chuàng)建快速動(dòng)態(tài)網(wǎng)頁(yè)的技術(shù)。它可以令開(kāi)發(fā)者只向服務(wù)器獲取數(shù)據(jù)(而不是圖片,HTML文檔等資源),互聯(lián)網(wǎng)資源的傳輸變得前所未有的輕量級(jí)和純粹,這激發(fā)了廣大開(kāi)發(fā)者的創(chuàng)造力,使各式各樣功能強(qiáng)大的網(wǎng)絡(luò)站點(diǎn),和互聯(lián)網(wǎng)應(yīng)用如雨后春筍一般冒出,不斷帶給人驚喜。
Ajax
是一種異步請(qǐng)求數(shù)據(jù)的web開(kāi)發(fā)技術(shù),對(duì)于改善用戶(hù)的體驗(yàn)和頁(yè)面性能很有幫助。簡(jiǎn)單地說(shuō),在不需要重新刷新頁(yè)面的情況下,Ajax 通過(guò)異步請(qǐng)求加載后臺(tái)數(shù)據(jù),并在網(wǎng)頁(yè)上呈現(xiàn)出來(lái)。常見(jiàn)運(yùn)用場(chǎng)景有表單驗(yàn)證是否登入成功、百度搜索下拉框提示和快遞單號(hào)查詢(xún)等等。
Ajax的目的是提高用戶(hù)體驗(yàn),較少網(wǎng)絡(luò)數(shù)據(jù)的傳輸量。同時(shí),由于AJAX請(qǐng)求獲取的是數(shù)據(jù)而不是HTML文檔,因此它也節(jié)省了網(wǎng)絡(luò)帶寬,讓互聯(lián)網(wǎng)用戶(hù)的網(wǎng)絡(luò)沖浪體驗(yàn)變得更加順暢。
Ajax相當(dāng)于在用戶(hù)和服務(wù)器之間加了一個(gè)中間層,使用戶(hù)操作與服務(wù)器響應(yīng)異步化。并不是所有的用戶(hù)請(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),而不阻塞用戶(hù)。達(dá)到無(wú)刷新的效果。
XMLHttpRequest
(記得考慮兼容性)let xhr = null;if (window.`XMLHttpRequest`) {// 兼容 IE7+, Firefox, Chrome, Opera, Safari xhr = new `XMLHttpRequest`(); } else {// 兼容 IE6, IE5 xhr = new ActiveXObject("Microsoft.XMLHTTP"); }
xhr.open(method, url, async); send(string);//`POST`請(qǐng)求時(shí)才使用字符串參數(shù),否則不用帶參數(shù)。
method
:請(qǐng)求的類(lèi)型;GET
或 POST
url
:文件在服務(wù)器上的位置
async
:true(異步)或 false(同步)
注意: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);});
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)可以在客戶(hù)端使用了;
status
?HTTP狀態(tài)碼(status)由三個(gè)十進(jìn)制數(shù)字組成,第一個(gè)十進(jìn)制數(shù)字定義了狀態(tài)碼的類(lèi)型,后兩個(gè)數(shù)字沒(méi)有分類(lèi)的作用。HTTP狀態(tài)碼共分為5種類(lèi)型:
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ò)。
僅記錄在 RFC2616 上的 HTTP 狀態(tài)碼就達(dá) 40 種,若再加上 WebDAV(RFC4918、5842)和附加 HTTP 狀態(tài)碼 (RFC6585)等擴(kuò)展,數(shù)量就達(dá) 60 余種。接下來(lái),我們就介紹一下這些具有代表性的一些狀態(tài)碼。
200
表示從客戶(hù)端發(fā)來(lái)的請(qǐng)求在服務(wù)器端被正常處理了。
204
表示請(qǐng)求處理成功,但沒(méi)有資源返回。
301
表示永久性重定向。該狀態(tài)碼表示請(qǐng)求的資源已被分配了新的URI,以后應(yīng)使用資源現(xiàn)在所指的URI。
302
表示臨時(shí)性重定向。
304
表示客戶(hù)端發(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)求訪問(wèn)資源,但因發(fā)生請(qǐng)求未滿(mǎn)足條件的情況后,直接返回304Modified(服務(wù)器端資源未改變,可直接使用客戶(hù)端未過(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)求需要用戶(hù)驗(yàn)證
403
表示對(duì)請(qǐng)求資源的訪問(wèn)被服務(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)求。
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ù)類(lèi)型,GET
只接受ASCII字符,而POST
沒(méi)有限制。
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)的輸入字段名稱(chēng)的總長(zhǎng)不超過(guò)1024個(gè)字符。
詳見(jiàn)本文內(nèi)容=>
//創(chuàng)建 XMLHttpRequest 對(duì)象var xhr = new XMLHttpRequest();//發(fā)送信息至服務(wù)器時(shí)內(nèi)容編碼類(lè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)求的類(lèi)型、URL 以及是否異步處理請(qǐng)求。xhr.open('GET',url,true);//發(fā)送請(qǐng)求xhr.send(null);
//字符串轉(zhuǎn)對(duì)象JSON.parse(json)eval('(' + jsonstr + ')') // 對(duì)象轉(zhuǎn)字符串JSON.stringify(json)
詳見(jiàn)本文內(nèi)容=>
詳見(jiàn)本文內(nèi)容=>
同源策略是瀏覽器的一個(gè)安全功能,不同源的客戶(hù)端腳本在沒(méi)有明確授權(quán)的情況下,不能讀寫(xiě)對(duì)方資源。所以xyz.com下的js腳本采用Ajax
讀取abc.com里面的文件數(shù)據(jù)是會(huì)被拒絕的。
同源策略限制了從同一個(gè)源加載的文檔或腳本如何與來(lái)自另一個(gè)源的資源進(jìn)行交互。這是一個(gè)用于隔離潛在惡意文件的重要安全機(jī)制。
舉個(gè)例子:
不受同源策略限制的情況:
頁(yè)面中的鏈接,重定向以及表單提交是不會(huì)受到同源策略限制的。
跨域資源的引入是可以的。但是js不能讀寫(xiě)加載的內(nèi)容。如嵌入到頁(yè)面中的<script src="..."></script>,<img>,<link>,<iframe>等。
JSONP 只能解決GET跨域(問(wèn)的最多)
原理:動(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ù)名稱(chēng)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: * //允許所有域名訪問(wèn),或者Access-Control-Allow-Origin: http://a.com //只允許所有域名訪問(wèn)
設(shè)置 document.domain
原理:相同主域名不同子域名下的頁(yè)面,可以設(shè)置document.domain
讓它們同域
限制:同域document提供的是頁(yè)面間的互操作,需要載入iframe頁(yè)面
// URL http://a.com/foovar 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()
方法允許來(lái)自不同源的腳本采用異步方式進(jìn)行有限的通信,可以實(shí)現(xiàn)跨文本檔、多窗口、跨域消息傳遞.
語(yǔ)法:
postMessage(data,origin)
用Apache做轉(zhuǎn)發(fā)(逆向代理),讓跨域變成同域
其實(shí)通過(guò) XMLHttpRequest
或者封裝后的框架進(jìn)行網(wǎng)絡(luò)請(qǐng)求,這種方式已經(jīng)有點(diǎn)老舊了,配置和調(diào)用方式非?;靵y,近幾年剛剛出來(lái)的Fetch提供了一個(gè)更好的替代方法,它不僅提供了一種簡(jiǎn)單,合乎邏輯的方式來(lái)跨網(wǎng)絡(luò)異步獲取資源,而且可以很容易地被其他技術(shù)使用。
聯(lián)系客服