1. 程式人生 > >深入理解AJAX

深入理解AJAX

異步請求 val span urn 導致 當前 msxml rac 利用

1.概述

ajax是asynchronous javascript and XML的簡寫,中文翻譯是異步的javascript和XML,這一技術能夠向服務器請求額外的數據而無須卸載頁面,會帶來更好的用戶體驗。雖然名字中包含XML,但ajax通信與數據格式無關

ajax包括以下幾步驟:1、創建AJAX對象;2、發出HTTP請求;3、接收服務器傳回的數據;4、更新網頁數據

概括起來,就是一句話,ajax通過原生的XMLHttpRequest對象發出HTTP請求,得到服務器返回的數據後,再進行處理

2.創建ajax對象

  ajax技術的核心是XMLHttpRequest對象(簡稱XHR),這是由微軟首先引入的一個特性,其他瀏覽器提供商後來都提供了相同的實現。XHR為向服務器發送請求和解析服務器響應提供了流暢的接口,能夠以異步方式從服務器取得更多信息,意味著用戶單擊後,可以不必刷新頁面也能取得新數據。

IE5是第一款引入XHR對象的瀏覽器。在IE5中,XHR對象是通過MSXML庫中的一個ActiveX對象實現的,而IE7+及其他標準瀏覽器都支持原生的XHR對象

創建一個XHR對象,也叫實例化一個XHR對象,因為XMLHTTPRequest()是一個構造函數。下面是創建XHR對象的兼容寫法

var xhr;
if(window.XMLHttpRequest){
    xhr = new XMLHttpRequest();
}else{
    xhr = new ActiveXObject(‘Microsoft.XMLHTTP‘);
}

[註意]如果要建立N個不同的請求,就要使用N個不同的XHR對象。當然可以重用已存在的XHR對象,但這會終止之前通過該對象掛起的任何請求。

3.發送請求

open()

在使用XHR對象時,要調用的第一個方法是open(),如下所示,該方法接受3個參數

xhr.open("get","example.php", false);

1、open()方法的第一個參數用於指定發送請求的方式,這個字符串,不區分大小寫,但通常使用大寫字母。"GET"和"POST"是得到廣泛支持的

   "GET"用於常規請求,它適用於當URL完全指定請求資源,當請求對服務器沒有任何副作用以及當服務器的響應是可緩存的情況下.

   "POST"方法常用於HTML表單。它在請求主體中包含額外數據且這些數據常存儲到服務器上的數據庫中。相同URL的重復POST請求從服務器得到的響應可能不同,同時不應該緩存使用這個方法的請求.

   除了"GET"和"POST"之外,參數還可以是"HEAD"、"OPTIONS"、"PUT"。而由於安全風險的原因,"CONNECT"、"TRACE"、"TRACK"被禁止使用.

2、open()方法的第二個參數是URL,該URL相對於執行代碼的當前頁面,且只能向同一個域中使用相同端口和協議的URL發送請求。如果URL與啟動請求的頁面有任何差別,都會引發安全錯誤

3、open()方法的第三個參數是表示是否異步發送請求的布爾值,如果不填寫,默認為true,表示異步發送

4、如果請求一個受密碼保護的URL,把用於認證的用戶名和密碼作為第4和第5個參數傳遞給open()方法

send()

  send()方法接收一個參數,即要作為請求主體發送的數據。調用send()方法後,請求被分派到服務器

  如果是GET方法,send()方法無參數,或參數為null;如果是POST方法,send()方法的參數為要發送的數據

xhr.open("get", "example.txt", false);
xhr.send(null);

4.接收響應

一個完整的HTTP響應由狀態碼、響應頭集合和響應主體組成。在收到響應後,這些都可以通過XHR對象的屬性和方法使用,主要有以下4個屬性

responseText: 作為響應主體被返回的文本(文本形式)
responseXML: 如果響應的內容類型是‘text/xml‘或‘application/xml‘,這個屬性中將保存著響應數據的XML DOM文檔(document形式)
status: HTTP狀態碼(數字形式)
statusText: HTTP狀態說明(文本形式)

在接收到響應後,第一步是檢查status屬性,以確定響應已經成功返回。一般來說,可以將HTTP狀態碼為200作為成功的標誌。此時,responseText屬性的內容已經就緒,而且在內容類型正確的情況下,responseXML也可以訪問了。此外,狀態碼為304表示請求的資源並沒有被修改,可以直接使用瀏覽器中緩存的版本;當然,也意味著響應是有效的

  無論內容類型是什麽,響應主體的內容都會保存到responseText屬性中,而對於非XML數據而言,responseXML屬性的值將為null

if((xhr.status >=200 && xhr.status < 300) || xhr.status == 304){
    alert(xhr.responseText);
}else{
    alert(‘request was unsuccessful:‘ + xhr.status);
}

5.同步請求

如果接受的是同步響應,則需要將open()方法的第三個參數設置為false,那麽send()方法將阻塞直到請求完成。一旦send()返回,僅需要檢查XHR對象的status和responseText屬性即可。

同步請求是吸引人的,但應該避免使用它們。客戶端javascript是單線程的,當send()方法阻塞時,它通常會導致整個瀏覽器UI凍結。如果連接的服務器響應慢,那麽用戶的瀏覽器將凍結。

6.異步請求

如果需要接收的是異步響應,這就需要檢測XHR對象的readyState屬性,該屬性表示請求/響應過程的當前活動階段。這個屬性可取的值如下:

0(UNSENT):未初始化。尚未調用open()方法
1(OPENED):啟動。已經調用open()方法,但尚未調用send()方法
2(HEADERS_RECEIVED):發送。己經調用send()方法,且接收到頭信息
3(LOADING):接收。已經接收到部分響應主體信息
4(DONE):完成。已經接收到全部響應數據,而且已經可以在客戶端使用了

理論上,只要readyState屬性值由一個值變成另一個值,都會觸發一次readystatechange事件。可以利用這個事件來檢測每次狀態變化後readyState的值。通常,我們對readyState值為4的階段感興趣,因為這時所有數據都已就緒。

[註意]必須在調用open()之前指定onreadystatechange 事件處理程序才能確保跨瀏覽器兼容性,否則將無法接收readyState屬性為0和1的情況。

   //創建xhr對象
    var xhr;
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject(‘Microsoft.XMLHTTP‘);
    }
    //異步接受響應
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                //實際操作
                result.innerHTML += xhr.responseText;
            }
        }
    }
    //發送請求
    xhr.open(‘get‘,‘message.xml‘,true);
    xhr.send();

7.請求超時

XHR對象的timeout屬性等於一個整數,表示多少毫秒後,如果請求仍然沒有得到結果,就會自動終止。該屬性默認等於0,表示沒有時間限制

  如果請求超時,將觸發ontimeout事件

  [註意]IE8-瀏覽器不支持該屬性

xhr.open(‘post‘,‘test.php‘,true);
xhr.ontimeout = function(){
    console.log(‘The request timed out.‘);
}
xhr.timeout = 1000;
xhr.send();

使用AJAX接收數據時,由於網絡和數據大小的原因,並不是立刻就可以在頁面中顯示出來。所以,更好的做法是,在接受數據的過程中,顯示一個類似loading的小圖片,並且禁用按鈕;當數據完全接收後,再隱藏該圖片,並啟用按鈕。

8.請求方式

GET

GET是最常見的請求類型,最常用於向服務器查詢某些信息,它適用於當URL完全指定請求資源,當請求對服務器沒有任何副作用以及當服務器的響應是可緩存的情況下。

【數據發送】

  使用GET方式發送請求時,數據被追加到open()方法中URL的末尾

  數據以問號開始,名和值之間用等號鏈接,名值對之間用和號(&)分隔。使用GET方式發送的數據常常被稱為查詢字符串

xhr.open("get","example.php?name1=value1&name2=value2",true)

【編碼】

  由於URL無法識別特殊字符,所以如果數據中包含特殊字符(如中文),則需要使用 encodeURIComponent() 進行編碼

  [註意] encodeURIComponent() 只是6種編解碼方法的一種。

var url = ‘test.php‘ +‘?name=‘  + encodeURIComponent("小火柴");
xhr.open(‘get‘,url,true);

上面的URL被編碼為

test.php?name=%E5%B0%8F%E7%81%AB%E6%9F%B4

【編碼函數】

  下面這個函數可以輔助向現有URL的末尾添加查詢字符串參數

function addURLParam(url,name,value){
    url += (url.indexOf("?") == -1 ? "?" : "&");
    url +=encodeURIComponent(name) + "=" + encodeURIComponent(value);
    return url;
}

【緩存】  

  在GET請求中,為了避免緩存的影響,可以向URL添加一個隨機數或時間戳

xhr.open(‘get‘,url+‘&‘+Number(new Date()),true);
xhr.open(‘get‘,url+‘&‘+Math.random(),true);

POST

使用頻率僅次於GET的是POST請求,通常用於服務器發送應該被保存的數據。"POST"方法常用於HTML表單。它在請求主體中包含額外數據且這些數據常存儲到服務器上的數據庫中。相同URL的重復POST請求從服務器得到的響應可能不同,同時不應該緩存使用這個方法的請求

POST請求應該把數據作為請求的主體提交,而GET請求傳統上不是這樣。POST請求的主體可以包含非常多的數據,而且格式不限。在open()方法第一個參數的位置傳入"post",就可以初始化一個POST請求

xhr.open("post","example.php",true);

【設置請求頭】

  發送POST請求的第二步就是向send()方法中傳入某些數據。由於XHR最初的設計主要是為了處理XML,因此可以在此傳入XML DOM文檔,傳入的文檔經序列化之後將作為請求主體被提交到服務器。當然,也可以在此傳入任何想發送到服務器的字符串

  默認情況下,服務器對POST請求和提交Web表單的請求並不會一視同仁。因此,服務器端必須有程序來讀取發送過來的原始數據,並從中解析出有用的部分。不過,可以使用XHR來模仿表單提交:首先將Content-Type頭部信息設置為application/x-www-form-urlencoded,也就是表單提交時的內容類型

xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");

 如果不設置Content-Type,發送給服務器的數據就不會出現在$_POSR超級全局變量中。這時要訪問同樣的數據,須借助$HTTP_RAW_POST_DATA

  如果對相同的頭調用多次setReQuestHeader(),新值不會取代之前指定的值。相反,HTTP請求將包含這個頭的多個副本或這個頭將指定多個值

【發送主體】

  接下來要以適當的格式創建一個字符串,並使用send()方法發送

  POST數據的格式與查詢字符串格式相同,名和值之間用等號鏈接,名值對之間用和號(&)分隔,如下所示

xhr.send(‘name="abc"&num=123‘);

【編碼和緩存】

  由於使用POST方式傳遞數據時,需要設置請求頭"content-type",這一步驟已經能夠自動對特殊字符(如中文)進行編碼,所以就不再需要使用encodeURIComponent()方法了

  POST請求主要用於數據提交,相同URL的重復POST請求從服務器得到的響應可能不同,所以不應該緩存使用POST方法的請求

【性能】

  GET對所發送信息的數量有限制,一般在2000個字符。與GET請求相比,POST請求消耗的資源會更多一些。從性能角度來看,以發送相同的數據計,GET請求的速度最多可POST請求的兩倍。

8.相應解碼

我們接收到的響應主體類型可以是多種形式的,包括字符串String、ArrayBuffer對象、二進制Blob對象、JSON對象、javascirpt文件及表示XML文檔的Document對象等。下面將針對不同的主體類型,進行相應的響應解碼。

在介紹響應解碼之前,要先了解XHR對象的屬性。一般地,如果接受的數據是字符串,使用responseText即可,這也是最常用的用於接收數據的屬性。但如果獲取了其他類型的數據,使用responseText可能就不太合適了。

【responseText】

  responseText屬性返回從服務器接收到的字符串,該屬性為只讀。如果本次請求沒有成功或者數據不完整,該屬性就會等於null。

  如果服務器返回的數據格式是JSON、字符串、javascript或XML,都可以使用responseText屬性

【response】

  response屬性為只讀,返回接收到的數據體。它的類型可以是ArrayBuffer、Blob、Document、JSON對象、或者一個字符串,這由XMLHttpRequest.responseType屬性的值決定

  如果本次請求沒有成功或者數據不完整,該屬性就會等於null

  [註意]IE9-瀏覽器不支持

【responseType】

  responseType屬性用來指定服務器返回數據(xhr.response)的類型

“”:字符串(默認值)
“arraybuffer”:ArrayBuffer對象
“blob”:Blob對象
“document”:Document對象
“json”:JSON對象
“text”:字符串

【responseXML】

  responseXML屬性返回從服務器接收到的Document對象,該屬性為只讀。如果本次請求沒有成功,或者數據不完整,或者不能被解析為XML或HTML,該屬性等於null

【overrideMimeType()】

  該方法用來指定服務器返回數據的MIME類型。該方法必須在send()之前調用

  傳統上,如果希望從服務器取回二進制數據,就要使用這個方法,人為將數據類型偽裝成文本數據

  但是,這種方法很麻煩,在XMLHttpRequest版本升級以後,一般采用指定responseType的方法

深入理解AJAX