先引入一下HTTP的請求過程還有介紹一下運行環境php
一個完整的HTTP請求過程,一般有下面7個步驟:html
創建TCP鏈接
Web瀏覽器向Web服務器發送請求命令
Web瀏覽器發送請求頭信息
Web服務器- 應答
Web服務器- 發送應答頭信息
Web服務器- 向瀏覽器發送數據
Web服務器- 關閉TCP鏈接web
Ajax必須在服務器環境下才能正常使用:ajax
可使用WampServer程序數據庫
AJAX簡介編程
Ajax(Asynchronous JavaScript and XML 異步的JavaScript與XML)是一種與服務器交換數據無需刷新網頁的技術,最先由Google公司在谷歌地圖裏使用,並迅速風靡。json
它是一系列web開發技術的集合,是一種使用不少的web技術,能在在客戶端開發異步web應用。利用Ajax,web應用能夠異步的發送數據獲取數據,而不干擾現有頁面的顯示和行爲。經過解耦數據接口層和展示層,Ajax容許web頁面或者其餘擴展的web應用動態的改變數據而不用從新加載整個頁面。實現一般選擇JSON代替XML,由於JSON更接近JavaScript,操做更加方便。segmentfault
Ajax不是一種技術,是一組技術。HTML和CSS用來組合標記和樣式信息。用戶能夠利用js訪問DOM對象負責動態展現。js和XMLHttpRequest對象提供一種瀏覽器和服務端異步互換數據的方法從而避免整個頁面加載。跨域
關於AJAX的歷史瀏覽器
在90年代中期,許多web站點徹底基於html頁面。每一個用戶行爲都須要從服務端從新加載頁面。這個過程很不方便,影響用戶體驗:全部的頁面內容消失,而後又出現。每次由於小部分改動須要瀏覽器從新加載頁面,全部內容都必須從新獲取,甚至只有不多的信息改變。這會額外增長服務端負載,浪費帶寬,影響性能。
在1996年,IE引入了iframe標籤來異步加載獲取內容。
在1998年,微軟的郵件組團隊利用客戶端腳本實現了第一個XMLHTTP組件。
在1999年,微軟在IE的默認頁面使用iframe技術動態更新新聞故事和股票行情,而且在IE5中建立了XMLHTTP ActiveX組件,這個技術隨後被Mozilla,Safari,Opera以及其餘瀏覽器採用,做爲XMLHttpRequest js對象。微軟在IE7中採用了原生的XMLHttpRequest模塊。IE仍然支持ActiveX版本,可是在Edge中不支持了。這種技術的使用在當時至關不明朗直到出如今大規模線上應用中,好比Outlook Web App (2000)和Oddpost。
谷歌在Gmail(2004)和Google Maps(2005)中廣發部署了符合標準的跨瀏覽器Ajax。在2004年10月Kayak.com的公測版本是首次大規模電子商務網站使用了他們當時稱爲"the xml htpp thing"的技術。
Jesse James Garrett在2005年2月18號發表的一篇題爲"Ajax: A New Approach to Web Applications"的論文中,基於Google 頁面中使用的技術,公開闡明瞭"Ajax"這個術語。
在2006年4月5號,W3C發表了第一個關於XMLHttpRequest對象的草案,嘗試創建一個官方的Web標準。關於XMLHttpRequest對象最新的草案是在2014年1月30號發佈的。
技術集
Ajax術語已經變成了web應用用來與服務端在幕後交流不打斷頁面當前狀態而使用的一組技術的表明。在Jesse James Garrett的論文裏創造的Ajax術語包括如下技術:
展示層的HTML(或者XHTML)和CSS
動態顯示和與數據交互的DOM對象
爲了交換數據的JOSN或者XML,爲了操縱數據的XSLT
爲了異步通訊的XMLHttpRequest對象
把這些技術整合起來的JavaScript
工做原理
傳統Web應用模型與使用Ajax的Web應用模型對比
傳統方式: 客戶端發起請求--等待-->服務器端處理---等待-->響應-->頁面載入 (請求錯誤時所有從新載入).
使用AJAX: 客戶端發起請求--->服務器端處理--->響應--->頁面載入(填寫時,即時更新,部分返回).
編寫AJAX
全部現代瀏覽器(IE7+、Firefox、Chrome、Safari 以及 Opera)均內建 XMLHttpRequest
對象。
Ajax編寫步驟
1.建立Ajax對象
2.鏈接服務器
3.發送請求
4.接受返回
建立Ajax對象:
//IE6以上 var oAjax = new XMLHttpRequest(); //IE6 var oAjax =new ActiveXObject("Microsoft.XMLHTTP")
鏈接服務器
open(method,url,async); open(發送請求方法"GET/POST" ,(請求地址"文件名") ,是否異步傳輸) 例: request.open("GET","get.json",true);
Ajax天生就是工做在異步模式的(異步爲true,同步false)
同步和異步
同步是指:發送方發出數據後,等接收方發回響應之後才發下一個數據包的通信方式。
異步是指:發送方發出數據後,不等接收方發回響應,接着發送下個數據包的通信方式。
發送請求send()
send(string)
在使用GET方式請求時無需填寫參數
在使用POST方式時參數表明着向服務器發送的數據
//完整的GET請求 var oAjax = new XMLHttpRequest();//建立Ajax對象 oAjax.open("GET","create.php",true);//鏈接服務器 oAjax.send();//發送請求 //完整的POST發送請求 var oAjax = new XMLHttpRequest();//建立 oAjax.open("POST","create.php",true);//"POST" oAjax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");//設置HTTP頭信息.必須在open與send之間,不然出現異常. oAjax.send("name=陳二狗&sex=男");//發送給服務器的內容
GET 仍是 POST?
與 POST 相比,GET 更簡單也更快,而且在大部分狀況下都能用。
然而,在如下狀況中,請使用 POST 請求:
沒法使用緩存文件(更新服務器上的文件或數據庫)
向服務器發送大量數據(POST 沒有數據量限制)
發送包含未知字符的用戶輸入時,POST 比 GET 更穩定也更可靠
接收返回信息
oAjax.onreadystatechange = function(){ //當請求狀態改變時要調用的事件處理器 alert(oAjax.readystate); }
只要readyState
屬性的值發生變化時,便會觸發一次readyStatechange
事件。能夠利用這個事件來檢測每次狀態變化後readyState的值。一般,咱們只對readyState值爲4的階段感興趣,由於這時全部數據都已經就緒,不過,必須在調用open()
以前指定onreadystatechange
事件處理程序才能確保跨瀏覽器兼容性。
下面來看一個例子:
var xhr = createXHR(); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) { alert(xhr.statusText); } else { alert("Request was unsuccessful: " + xhr.status); } } }; xhr.open("get", "example.txt", true); xhr.send(null);
XMLHttpRequest
這個對象的屬性:
onreadystatechange 每次狀態改變所觸發事件的事件處理程序。
responseText 從服務器進程返回數據的字符串形式。
responseXML 從服務器進程返回的DOM兼容的文檔數據對象。
status 從服務器返回的數字代碼,好比常見的404(未找到)和200(已就緒)
status Text 伴隨狀態碼的字符串信息
當XHR對象把一個HTTP請求發送到服務器的過程當中會經歷幾個狀態,直到請求被處理,而後才接收一個迴應。readyState
就是XHR請求的狀態屬性,它自己有5個屬性值:
0(未初始化)尚未調用open()方法 1(載入)已調用send()方法,正在發送請求 2(載入完成)send()方法完成,已收到所有響應內容 3(解析)正在解析響應內容 4(完成)響應內容解析完成,能夠再客戶端使用了
status和statusText
statusText
是響應返回的文本信息,僅當readyState
值爲3或4的時候才能使用。當readyState
爲其它值時視圖存取statusText
屬性將引起異常。
XHR的方法
方法 | 描述 |
---|---|
abort() | 致使當前正在執行的請求被取消 |
getAllResponseHeaders() | 返回包含全部響應頭的名稱和值的單個字符 |
getResponseHeader(name) | 返回響應頭中指定的名稱和值 |
open(method,url,async,username,pwd) | 設置HTTP方法(get或post)等 |
send(content) | 發出帶有指定主體內容的請求 |
setRequestHeader(name,value) | 使用指定的名稱和值設置請求頭 |
//基本完整的一個Ajax請求 var request = new XMLHttpRequest(); request.open("GET","get.json",true); request.onreadystatechange = function () { if (request.readyState === 4) { if (request.status === 200) { //響應成功,作一些事情 } else { //響應失敗,作一些事情 } } };
使用函數簡單的封裝一個get請求
/** * 一個簡單的異步get請求 * @param {String} url 請求地址,文件名 * @param {Function} fnSucc 請求成功時執行的函數,形參爲爲獲取的字符串值. * @param {Function} fnFaild 請求失敗執行的函數,可選參數 */ function get(url, fnSucc, fnFaild) { //1.建立ajax對象 var oAjax = null //此處必須須要使用window.的方式,表示爲window對象的一個屬性.不存在是值爲undefined,進入else/若直接使用XMLHttpRequest在不支持的狀況下會報錯 if (window.XMLHttpRequest) { oAjax = new XMLHttpRequest(); } else { //IE6以上,如今應該不須要考慮IE6了 oAjax = new ActiveXObject("Microsoft.XMLHTTP"); } //2.鏈接服務器 //open(方法,url,是否異步) oAjax.open("GET", url, true); //3.發送請求 oAjax.send(); //4.接收返回 //OnRedayStateChange事件 oAjax.onreadystatechange = function () { if (oAjax.readyState === 4) { if (oAjax.status === 200) { fnSucc(oAjax.responseText); } else { if (fnFaild) { fnFaild(); } } } }; }
這樣的封裝還不夠,緣由以下:
目前方法只能使用get請求,而不能使用post請求,而在用戶註冊時必須使用POST,由於POST,如今不夠完整。
目前請求參數只能直接寫在url裏,不利於動態獲取數據,應該使用參數解析的方式,便於使用。
get請求方式請求緩存問題。
封裝以下:
/** * AJAX函數封裝 * @param {string} url 請求地址(必須) * @param {object} options 發送請求的選項參數 * @config {string} [options.type] 請求發送的類型。默認爲GET。 * @config {Object} [options.data] 須要發送的數據。 * @config {Function} [options.onsuccess] 請求成功時觸發,function(oAjax.responseText, oAjax)。(必須) * @config {Function} [options.onfail] 請求失敗時觸發,function(oAjax)。(oAJax爲XMLHttpRequest對象) * *@returns {XMLHttpRequest} 發送請求的XMLHttpRequest對象 */ function AJAX(url, options) { //1.建立ajax對象 var oAjax = null; /** * 此處必須須要使用window.的方式,表示爲window對象的一個屬性.不存在時值爲undefined,進入else * 若直接使用XMLHttpRequest,在不支持的狀況下會報錯 **/ if (window.XMLHttpRequest) { //IE6以上 oAjax = new XMLHttpRequest(); } else { oAjax = new ActiveXObject("Microsoft.XMLHTTP"); } //2.鏈接服務器 //open(方法,url,是否異步) var param = ""; //請求參數。 //只有data存在,且爲對象使才執行 var data = options.data ? options.data : -1; //緩存data if (typeof (data) === "object") { for (var key in data) { //請求參數拼接 if (data.hasOwnProperty(key)) { param += key + "=" + data[key] + "&"; } } param.replace(/&$/, ""); } else { param = "timestamp=" + new Date().getTime(); } //3.發送請求 var type = options.type ? options.type.toUpperCase() : "GET"; if (type === "GET") { oAjax.open("GET", url + "?" + param, true); oAjax.send(); } else { oAjax.open("POST", url, true); oAjax.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); oAjax.send(param); } //4.接收返回 //OnRedayStateChange事件 oAjax.onreadystatechange = function () { if (oAjax.readyState === 4) { if (oAjax.status === 200) { //請求成功。形參爲獲取到的字符串形式的響應數據 options.onsuccess(oAjax.responseText, oAjax); } else { //先判斷是否存在請求失敗函數 //存在時,形參爲XMLHttpRequest對象,便於進行錯誤進行處理 if (options.onfail) { options.onfail(oAjax); } } } }; return oAjax;//發送請求的XMLHttpRequest對象 }
options是一個對象,裏面能夠包括的參數爲:
type: post或者get,能夠有一個默認值
data: 發送的數據,爲一個鍵值對象或者爲一個用&鏈接的賦值字符串
onsuccess: 成功時的調用函數
onfail: 失敗時的調用函數
應用優點
· AJAX不是一種新的編程語言,而是一種用於建立更好更快以及交互性更強的Web應用程序的技術。
· 使用Javascript向服務器提出請求並處理響應而不阻塞用戶!核心對象XMLHTTPRequest。經過這個對象,您的 JavaScript 可在不重載頁面的狀況與Web服務器交換數據,即在不須要刷新頁面的狀況下,就能夠產生局部刷新的效果。
· AJAX 在瀏覽器與 Web 服務器之間使用異步數據傳輸(HTTP 請求),這樣就可以使網頁從服務器請求少許的信息,而不是整個頁面。
· AJAX 可以使因特網應用程序更小、更快,更友好。
· AJAX 是一種獨立於 Web 服務器軟件的瀏覽器技術。
· AJAX 基於下列 Web 標準:
JavaScriptXMLHTMLCSS在 AJAX 中使用的 Web 標準已被良好定義,並被全部的主流瀏覽器支持。AJAX 應用程序獨立於瀏覽器和平臺。
Web 應用程序較桌面應用程序有諸多優點;它們可以涉及廣大的用戶,它們更易安裝及維護,也更易開發。
不過,因特網應用程序並不像傳統的桌面應用程序那樣完善且友好。
經過 AJAX,因特網應用程序能夠變得更完善,更友好。
弊端
· 若是用戶瀏覽器不支持JavaScript或者XMLHttpRequest,或者禁用這種功能,則不能正常使用依賴Ajax的頁面。簡單設備(例如智能手機,pad)可能不支持須要的這些技術。讓用戶使用這種功能的惟一方法是回退到沒有JavaScript方法。能夠同經過確保連接表單正確解析而不是僅僅依賴Ajax來實現相關功能。
· 一樣的,一些使用Ajax的Web應用對屏幕閱讀技術不友好,例如JAWS。WAI-ARIA標準提供了一種方法在這種狀況下提供提示。
· 屏幕閱讀器可使用Ajax,可是也可能不能正確的讀取動態產生的內容。
· 同源策略阻止了一些Ajax技術跨域使用,儘管W3C有關於XMLHttpRequest對象的草案容許這個功能。經過使用一個特別的跨域通道例如頁面中的iframe或者使用JSONP能夠跨過這種安全限制。
· 異步的回調編程可能致使負責的代碼難以維護,調試和測試。
· 由於Ajax的異步特性,客戶端發送接收到每塊數據都發生在專門爲改事件創建的鏈接上。這就爲每一個行爲增長一種須要,那就是客戶端必須輪詢服務端,而不是監聽,這就會致使額外開銷。這種開銷會致使Ajax應用有更高的延遲相比於利用websocket技術獲取數據。
· 在非HTML5瀏覽器中,使用Ajax請求建立的動態頁面不能自動的註冊到瀏覽器的歷史記錄中,因此在點擊瀏覽器"回退"按鈕時,瀏覽器不會回到Ajax發生以前的狀態,可是會回退到上次訪問的頁面。這種在頁面之間導航而不是在頁面狀態之間導航的行爲可能不是想要的,可是若是須要追蹤頁面狀態,那麼對於非HTML5的瀏覽器一個變通的方案就是使用非透明的iframe觸發瀏覽器歷史記錄的改變。另外一個變通方法就是利用Ajax技術更改URL的片斷標識符(URL中在"#"以後的部分)。HTML5提供了一個擴展的API標準來操做瀏覽器歷史記錄。
· 動態web頁面更新致使很難記標籤,返回應用的特性狀態。這種問題的解決辦法也是存在的,也是利用URL的片斷標識符。HTML5提供瞭解決上面問題的方法。
· 因爲Ajax應用的特性,動態頁面更新可能會打斷用戶交互,特別是當網絡鏈接很慢或者不可能的時候。例如,編輯一個搜索框可能會觸發一個服務端查詢,可是用戶可能不知道查詢結束時會彈出一個框,若是此時網絡很慢,彈窗可能會在一個不恰當的時候彈出,當用戶已經開始處理其餘的事情時。
· 除了Google,大多數網絡爬蟲不能執行js代碼,因此爲了被搜索引擎收錄,Web應用必須爲那些經過Ajax獲取內容的頁面提供一個備選頁面。
雖然AJAX存在不少弊端,可是隨着技術的發展,不少弊端都可以很好地來避免。
參考: