標籤:== run send 處理 padding 非同步 文章 code 應用程式
曾經有一段時期,因為開發人員對JavaScript的濫用導致其遭受了一段時間的冷門時期,不被大家看好,後來,到了2005年,Google公司的很多技術都是用了ajax之後,JavaScript才又火熱了起來,可以說,是Ajax拯救了JavaScript,就目前來說,熟練使用Ajax已經成為了所有web開發人員必須掌握的技能。那麼Ajax又是什麼呢? 它的作用是什麼呢?
第一部分:Ajax簡介
Ajax即Asynchronous JavaScript +XML的簡寫,這一技術能夠向伺服器請求額外的資料而無需卸載頁面,會帶來更好地使用者體驗。Ajax的核心是XMLHttpRequest對象(簡稱XHR,這一對象受到chrome、safari、FF、opera等主流瀏覽器的支援),這是由微軟首先引入的一個特性,IE 瀏覽器(5和6)使用 ActiveXObject,後來瀏覽器供應商都提供了相同的實現。XHR對象的存在,意味著當使用者點擊之後,不必重新整理頁面也可以從後台取得新資料,也就是說,可以試用XHR對象取得新資料,然後通過DOM方式將新資料插入到頁面中,達到對網頁的某部分進行更新的效果。值得注意的是:雖然,Ajax中包含了xml,但是我們在無需重新整理頁面就得到的資料不一定是xml資料,比如可以是文本資料或者JSON資料。
第二部分:XHR對象的建立
上面講到,Ajax的核心是XMLHttpRequest對象,那麼我們如何建立一個XMLHttpRequest對象呢?
首先,我們應當知道:所有瀏覽器都支援XMLHttpRequest對象,其中IE5和IE6使用ActiveXObject對象。並且現在所有瀏覽器(IE7+、FireFox、Chrome、Safari以及Opera)均內建了XMLHttpRequest對象。於是建立XMLHttpRequest對象的文法是:
1 |
var xhr = new XMLHttpRequest(); |
剛剛提到老版本的Internet Explorer(IE5和IE6)使用的是ActiveXObject對象,所以文法是:
1 |
var axo = new ActiveXObject( "Microsoft.XMLHTTP" ); |
注意:其中傳入的“Microsoft.XMLHTTP”是不能改變的。
於是,為了應對所有的現代瀏覽器(包括IE5和IE6),請首先檢查是否支援XMLHttpRequest對象:如果支援,則建立XMLHttpRequest對象;如果不支援,則建立ActiveXObject對象:
123456789 |
var xmlHttp= null ; if (window.XMLHttpRequest) { xmlHttp= new XMLHttpRequest(); } else { xlmHttp= new ActiveXObject( "Microsoft.XMLHTTP" ); } |
關於這個應對所有現代瀏覽器的代碼應當注意:
- 我將xmlHttp的值設定為null,是因為null值表示一個Null 物件指標,而這也正是使用typeof操作符檢測null值是會返回“object”的原因,因此:如果定義的變數準備在將來用於儲存對象,那麼最好將該變數初始化為null而不是其他值。
- 之所以可以試用window.XMLHttpRequest來檢測其是否存在,是因為XMLHttpRequest是window對象的屬性。
第三部分:XHR對象的用法(屬性與方法等)
上面兩部分,我們介紹XHR對象是什麼以及怎麼建立,這一部分我將談一談XHR對象的用法。
⑴.open()方法
既然XHR是一個對象,那麼它就一定有自己的屬性和方法。在使用XHR對象時,要調用的第一個方法是open()。它接受3個參數:
- 要發送的請求的類型:get、post、put、delete等等。
- 請求的URL(這個URL既可以是絕對路徑,也可以是相對路徑)。
- 是否非同步發送請求的布爾值:true表示非同步發送請求,false表示同步發送請求。
(補充:我們不推薦使用async=false,因為這樣JavaScript會等到伺服器響應就緒才繼續進行,如果伺服器繁忙或緩慢,那麼應用程式會掛起或停止)
舉例如下:
1 |
xhr.open( "get" , "example.php" , true ); |
此時,這段代碼會啟動一個針對example.php的GET請求。注意:open()方法並不會真正的發送請求而只是啟動一個請求以備發送。那麼怎麼才能發送特定的請求呢,這是就要用到send()方法了。
⑵.send()方法
剛剛說到open()方法,只是開啟(open),還沒有發送,而send才是真正地發送。它接受一個參數:
注意:如果不需要通過請求主體發送資料,則必須傳入null。一般get請求不需要傳入參數,而對於post請求,如果需要像 HTML 表單那樣 POST 資料,請使用 setRequestHeader() 來添加 HTTP 頭。然後在 send() 方法中規定您希望發送的資料。這一部分會詳細介紹,下面舉一個簡單例子:
12 |
xhr.open( "get" , "example.php" , true ); xhr.send( null ); |
(3).XHR對象的幾個屬性
通過send()發送之後,會接受到響應,響應的資料會自動填滿XHR對象的屬性。主要有以下幾種:
- responseText:作為響應主體被返回的文本
- responseXML:如果響應的內容類型是"text/xml"或"application/xml",這個屬性中將儲存包含著相應資料的XML DOM文檔。
- status:響應的http狀態
- statusText:Http狀態的說明
在接收到響應後,一般是先檢查status屬性,來確定響應是否成功返回,一般狀態碼200表示成功(以2開頭即表示成功),這是responseText就可以被訪問了。而狀態碼為304表示請求的資源並沒有被修改,可以直接使用瀏覽器中緩衝的版本,因此這種響應也是有效。於是可以通過下面的代碼檢測這兩種狀態:
1234567 |
xhr.open( "get" , "example.php" , false ); xhr.send( null ); if ((xhr.status>=200&&xhr.status<300)||xhr.status==304){ alert(xhr.responseText); } else { alert( "Request waw unseccessful:" + "xhr.status" ); } |
XHR對象的readystate屬性
使用Ajax我們當然還是希望發送非同步請求的:如果發送同步請求,那麼一旦網卡住了,這個頁面就不會有任何反應而是繼續等待響應,但是發送非同步請求,即使網卡住,也不用擔心,因為它是非同步。而readystate屬性可以檢測到請求/響應過程的當前活動階段。它有5個取值,分別如下:
關鍵:只要readystate的值改變(比如從0變為1,從1變為2等等),那麼每次地改變都會觸發readystatechange事件。並且可以通過這個時間檢測每次狀態變化後的readystate的值。當值為4是最重要的,因為這事所有的資料已經準備就緒。看一個例子:
123456789101112 |
var xhr= new XMLHttpRequest(); xhr.open( "get" , "example.php" , false ); xhr.onreadystatechange= function (){ if (readyState==4){ if ((xhr.status>=200&&xhr.status<300)||xhr.status==304){ alert(xhr.responseText); } else { alert( "Request waw unseccessful:" + "xhr.status" ); } } }; xhr.send( null ); |
注意以下幾點:
- xhr.onreadystatechange前面有一個on,這是因為我們使用的是DOM0級方法為XHR對象添加了時間處理常式,沒有利用addEventListener這種DOM2級方法,是因為並非所有的瀏覽器都支援DOM2級方法。
- 這個例子中我們沒有使用this對象,是因為onreadystatechange時間處理常式的範圍問題。如果使用this對象,在有的瀏覽器中會導致函數執行失敗或者導致發生錯誤。因此,使用實際的XHR對象執行個體便利那個是一種較為可靠的方式。
(4).abort()方法
在接受到響應之前,我們還可以使用abort()方法來取消非同步請求,如下所示:
在調用了這個方法之後,XHR對象會停止觸發事件,而且也不再允許訪問任何與響應有關的對象屬性。
(5)setRequestHeader()方法、getResponseHeader()方法、getAllResponseHeader()方法在第四部分介紹完之後講解
第四部分:HTTP頭部資訊
因為使用Ajax和後台互動,那麼就一定離不開http協議了。而HTTP請求和響應都會帶有相應的頭部資訊。
在預設情況下,在發送XHR請求的同時,還會發送以下頭部資訊。
- Accept:瀏覽器能夠處理的內容類型
- Accept-Charset:瀏覽器能夠顯示的字元集
- Accept-Encodding:瀏覽器能夠處理的壓縮編碼
- Accept-Language:瀏覽器當前設定的語言
- Connection:瀏覽器與伺服器之間連結的類型
- Cookie:當前版面設定的任何Cookie
- Host:發出請求的頁面所在的域
- Referer:發出請求頁面的URI
- User-Agent:瀏覽器的使用者代理程式字串
下面這張圖片是我的chrome瀏覽器開發人員工具下的network中截屏所得,大家可以對照參考:
我們還可以通過setRequestHeader()方法來設定自訂的要求標頭部資訊。這個方法接收兩個參數:頭部欄位的名稱和頭部欄位的值。並且我們必須在open()方法之後,在send()方法之前來調用setRequestHeader()方法。舉例如下:
1234 |
var xhr= new XMLHttpRequest(); xhr.open( "get" , "example.php" , true ); xhr.setRequestHeader( "myHeader" , "myValue" ); xhr.send( null ); |
這裡只需要注意:這裡傳入的頭部欄位的名稱最好是自訂的,而不要使用瀏覽器正常發送的欄位名稱,否則有可能會影響瀏覽器的響應。(因為有的瀏覽器允許開發人員重寫預設的頭部資訊,而有的瀏覽器是不允許開發人員重寫預設的頭部資訊的)。
除了可以為要求標頭部增加自訂的頭部欄位,我們還可以擷取頭部欄位。我們可以調用XHR對象的getResponseHeader()方法並傳入一個頭部欄位名稱,便可以獲得回應標頭部資訊。還可以調用XHR對象的getAllResponseHeaders()方法取得一個包含所有頭部資訊的長字串。
如下所示:
12 |
var myHeader=xhr.getResponseHeader( "myHeader" ); var allHeaders=xhr.getAllResponseHeaders(); |
第五部分:GET請求
get請求用於向伺服器查詢某些資訊。注意,查詢字串(成對的名稱和數值)是在 GET 請求的 URL 中發送的。 但是,有時候可能會出現問題,即查詢字串的格式有問題。查詢字串的每個參數的名稱和值都必須使用encodeURIComponent()進行編碼,然後才能放到URL的末尾;而且所有的名值對都必須用&分隔。如下所示:
1 |
xhr.open( "get" , "example.php?name1=value1&name2=value2" , true ); |
而下面的這個函數可以輔助向現有的URI的末尾添加查詢字串:
123456789 |
function addURIParam(url,name,vaule){ url+=(url.indexOf( "?" )==-1? "?" : "&" ); url+=encodeURIComponent(name)+ "=" +encodeURIComponent(value); return url; } var url= "example" ; url=addURIParam(url, "name" , "zzw" ); url=addURIParam(url, "sex" , "male" ); xhr.open( "get" ,url, false ); |
實際上,函數中的第一句是先判斷url後面有沒有查詢字串,如果沒有,就添加?,如果有,就添加&,因此,最終的url為"example.php?name=zzw&sex=male"。
另外,對於get請求需要注意:
- GET請求可以被緩衝
- GET請求保留在記錄中
- GET請求可被收藏為書籤(因為查詢字串就在url中)
- GET請求不應該在處理敏感性資料時使用(因為查詢字串是暴露的,任何人都可以看到)
- GET請求有長度限制,超過最大長度後一般無法提交,更多看這裡
- GET請求只應當用於取回資料
第六部分:POST請求
POST請求的使用頻率僅次於GET請求,通常用於向伺服器中發送應該被儲存的資料。請注意,查詢字串(成對的名稱和數值)是在 POST 請求的 HTTP 訊息主體中發送的。而GET請求卻不是這樣的。POST請求的主體可以包含很多的資料,而且格式不限。
預設情況下,伺服器對post請求和提交web表單的請求不會一視同仁,因此,我們可以試用XHR對象和模仿表單提交:首先將Content-Type頭部資訊設定為application/x-www-form-urlencoded,也就模仿成了表單提交時的內容類型(贊一個!)。接著需要在以適當的格式建立一個字串,post資料的格式和查詢字串格式相同,如果需要將頁面中表單的資料序列化,在通過XHR發送到伺服器,那麼就要使用serialize()函數來建立這個字串。下面舉兩個例子:
123 |
xhr.open( "POST" , "example.php" , true ); xhr.setRequestHeader( "Content-type" , "application/x-www-form-urlencoded" ); xhr.send( "fname=Bill&lname=Gates" ); |
這裡我們沒有將字串序列化。
1234 |
xhr.open( "POST" , "example.php" , true ); xhr.setRequestHeader( "Content-type" , "application/x-www-form-urlencoded" ); var form=document.getElementById( "user-info" ); xhr.send(serialize(form)); |
這裡我們使用serialize()函數進行了序列化。
另外,對於post請求需要注意:
- POST請求不會被緩衝
- POST請求不會保留在瀏覽器記錄中
- POST請求不能被收藏為書籤(因為發送的字串不會出現在url中)
- POST請求對資料長度沒有要求
講過了POST請求和GET請求,那麼它們之間的區別是什麼呢?
第七部分:同源策略
通過XHR實現Ajax通訊的一個主要限制,來源於跨域安全性原則,又稱為同源策略。那麼什麼是同源策略呢?
同源策略,它是由Netscape提出的一個著名的安全性原則,預設情況下,XHR對象只能訪問與包含他的頁面位於同一個域中的資源,這種安全性原則可以預防某些惡意行為。現在所有支援JavaScript的瀏覽器都會使用這個策略,這種安全性原則可以預防某些惡意行為,比如,A網站是一家銀行,如果使用者登陸了以後,其他的網站可以讀取A網站的Cookie,那麼其他網站就可以為所欲為了。但是,實現合理的跨域請求對開發某些瀏覽器的應用程式也是至關重要的。後續的文章我會介紹跨域資源共用的知識。這裡僅介紹同源策略。
所謂同源是指:協議、網域名稱和連接埠相同。
舉例說:http://www.cnblogs.com/dir/page.html這個網址。
協議:http://
網域名稱:www.cnblogs.com
連接埠:80(預設連接埠可以省略)。
對於這個網址的同源情況如下:
- http://www.cnblogs.com/cat/index.html (同源)
- http://cnblogs.com/dir/page.html(不同源-網域名稱不同)
- https://cnblogs.com/dir/page.html(不同源-協議不同)
- http://www.cnblogs.com:81/dir/page.html(不同源-連接埠不同)
第八部分:應用
1.原生ajax的使用
在控制台的結果如下所示:
2. jQuery中ajax的使用
自己選擇的路、跪著也要把它走完。
JavaScript Ajax之美~