js中的ajax的運用


XMLHttpRequest對象

IE7+,FireFox,Chrome,Opera,Safari創建XHR對象:

var xhr=new XMLHttpRequest(); 

創建XHR對象的兼容性寫法:

 1 function createXHR(){
 2   if(typeof XMLHttpRequest!="undefined"){
 3     return new XMLHttpRequest();
 4   }else if(typeof ActiveXObject!="undefined"){
 5     if(typeof arguments.callee.activeXString!="string"){
 6       var versions=["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],
 7           i,len;
 8       for(i=0,len=versions.length;i<len;i++){
 9         try{
10           new ActiveXObject(versions[i]);
11           arguments.callee.activeXString=versions[i];
12           break;
13         }catch(ex){
14 
15         }
16       }
17     }
18     return new ActiveXObject(arguments.callee.activeXString);
19   }else{
20     throw new Error("NO XHR object available");
21   }
22 }
23 
24 var xhr=new createXHR();

XHR用法

發送同步請求

使用 XHR 時,首先要調用 open() 方法,傳遞三個參數:

  1. 要發送的請求類型( get , post 等)
  2. 請求的 url
  3. 是否異步發送

要發送特定的請求,必需像下面這樣調用 send() 方法

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

這里 send() 方法接收一個參數,作為請求主體發送的數據。如果不需要通過請求主體發送數據,這里必須傳入 null ,因為這個參數對有些瀏覽器來說是必需的。調用 send() 之后,請求就會被分派到服務器。

由於這次請求是同步的,JavaScript 代碼會等到服務器響應之后再繼續執行。在收到響應之后,相應的數據會自動填充XHR對象的屬性,相關的屬性簡介如下:

  • responseText: 作為響應主體被返回的文本。
  • responseXML: 如果響應的內容類型是 “text/xml”或”application/xml”,這個屬性中將保存包含着相應數據的XML DOM文檔。
  • status: 響應的HTTP狀態。
  • statusText: HTTP狀態的說明。

接受響應之后,第一步是檢查 status 屬性,以確定響應已經成功返回。狀態碼:

  • 200 表示成功
  • 304 表示請求的資源並沒有修改,可以直接使用瀏覽器中緩存的版本,響應也是有效的

像下面這樣檢查上述這兩種狀態碼的狀態:

1 xhr.open("get","example.txt",false);
2 xhr.send(null);
3 
4 if((xhr.status >= 200 && xhr.status < 300)|| xhr.status == 304){
5   alert(xhr.responseText);
6 }else{
7   alert("Request was unsuccessful: " + xhr.status);
8 }

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

發送異步請求

向前面這樣發送同步請求當然沒問題,但多數情況下,我們還是要發送異步請求,才能讓 JavaScript 繼續執行而不必等待響應。此時,可以檢測 XHR 對象的 readyState 屬性,該屬性表示請求/響應過程中的當前活動階段。這個屬性可取的值如下:

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

只要 readyState 屬性的值由一個值變為另一個值,都會觸發一次 readystatechange 事件。可以利用這個事件來檢測每次狀態變化后的 readyState 的值,通常,我們只對 readyState 值為 4 的階段感興趣,因為這時所有的數據都已經就緒。不過,必須在調用 open() 之前指定 onreadyState 事件處理程序才能確保跨瀏覽器兼容性。例子如下:

 1 var xhr = createXHR();
 2 xhr.onreadyStatechange = function(){
 3   if(xhr.readyState == 4){
 4     if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
 5       alert(xhr.responseText);
 6     }else{
 7       alert("Request was unsuccessful:" + xhr.status );
 8     }
 9   }
10 };
11 
12 xhr.open("get","example.txt",true);
13 xhr.send(null);

另外,在接收到響應之前還可以調用 abort() 方法來取消異步請求,如下所示:

xhr.absort(); 

調用這個方法后,XHR 對象會停止觸發事件,而且也不再允許訪問任何與響應有關的對象屬性。

HTTP頭部信息

每個 HTTP 請求和響應都會帶有響應的頭部信息,有的對開發人員有用,有的也沒有什么用,XHR 對象也提供了操作這兩種頭部(即請求頭部和響應頭部)信息的方法。 默認情況下,在發送 XHR 請求的同事,還會發送下列頭部信息。

  • Accept: 瀏覽器能夠處理的內容類型。
  • Accept-Charset: 瀏覽器能夠顯示的字符集。
  • Accept-Encoding: 瀏覽器能夠處理的壓縮編碼。
  • Accept-Language: 瀏覽器當前設置的語言。
  • Connection: 瀏覽器與服務器之間連接的類型。
  • Cookie: 當前頁面設置的語言。
  • Host: 發出請求的頁面所在的域。
  • Referer: 發出請求的頁面的URI。
  • User-Agent: 瀏覽器的用戶代理字符串。

使用 setRequestHeader() 方法可以設置自定義的請求頭部信息。這個方法接受兩個參數:頭部字段的名稱和頭部字段的值。要成功發送請求頭部信息,必須在調用 open() 方法之后且調用 send() 方法之前調用 setRequestHeader(),如下面的例子所示。

 1 var xhr = createXHR();
 2 xhr.onreadystatechange = function(){
 3   if(xhr.readyState == 4){
 4     if((xhr.status >= 200 && xhr.status < 300) || xhr.status = 304){
 5       alert(xhr.responseText);
 6     }else{
 7       alert("Request was unsuccessful: " + xhr.status);
 8     }
 9   }
10 };
11 
12 xhr.open("get","example.php",true);
13 xhr.setRequestHeader("MyHeader","MyValue");
14 xhr.send(null);

服務器在接收到這種自定義的頭部信息之后,可移植性響應的后續操作。建議使用自定義的頭部字段名稱,不要使用瀏覽器正常發送的字段名稱。

調用 XHR 對象的 getResponseHeader() 方法並傳入頭部字段名稱,可以取得相應的響應頭部信息。而調用 getAllResponseHeaders() 方法可以取得一個包含所有頭部信息的長字符串。看下面的例子:

 1 var myHeader=xhr.getResponseHeader("MyHeader"); 2 var allHeader=xhr.getAllResponseHeaders();  

GET請求

GET 是最常見的請求類型,最常用於向服務器查詢某些信息。必要時,可以講查詢字符串參數追加到 URL 的末尾,以便將信息發送給服務器。對 XHR 而言,位於傳入 open() 方法的 URL 末尾的查詢字符串必須經過正確的編碼才行。

使用 GET 請求經常會發生的一個錯誤,及時查詢字符串的格式有問題。查詢字符串中每個參數的名稱和值必須使用 encodeURIComponent() 進行編碼,然后才能放到 URL 的末尾;而且所有名-值對都必須由和號(&)分隔,例子如下:

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

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

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

使用方法:

1 var url="example.php";
2 
3 //添加參數
4 url = addURLParam(url,"name","Nocholas");
5 url = addRULParam(rul,"book","Professional JavaScript");
6 
7 //初始化請求
8 xhr.open("get",url,false);

POST請求

POST 請求通常用於向服務器發送應該被保存的數據。POST 請求應該吧數據作為請求的主體提交,而 GET 請求傳統上不是這樣。

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

 1 function submitData(){
 2   var xhr = createXHR();
 3   xhr.onreadystatechange = function(){
 4     if(xhr.readyState == 4){
 5       if((xhr.status >= 200 && xhr.status < 300) || xhr.status = 304){
 6         alert(xhr.responseText);
 7       }else{
 8         alert("Request was unsuccessful: " + xhr.status);
 9       }
10     }
11   };
12   xhr.open("post","example.php",true);
13   xhr.setRequestHeader("Content-Type","application/x-www-from-urlencoded");
14   var form=document.getElementById("user-info");
15   xhr.send(serialize(form));
16 }

這個函數可以將 ID 為 “user-info” 的表單中的數據序列化之后發送給服務器。

XMLHttpRequest2級

XMLHttpRequest 1級只是把已有的 XHR 對象的實現細節描述了出來。而 XMLHttpRequest2級則進一步發展了 XHR。並非所有瀏覽器都完整地實現了 XMLHttpRequest2級規范。

FormData

現代 Web 應用中頻繁使用的一項功能就是表單數據的序列化,XMLHttpRequest2級為此定義了 FormData 類型。FormData 為序列化表單以及創建與表單格式相同的數據提供了便利。下面代碼創建了 FormData 對象,並向其中添加了一些數據。

var data = new FormData(); data.append("name","Nicholas"); 

這個 append() 方法接受兩個參數:鍵和值,分別對應表單字段的名字和字段中包含的值。可以像這樣添加任意多的鍵值對。而通過向 FormData 構造函數中傳入表單元素,也可以用表單元素的數據預先向其中填入鍵值對:

var data=new FormData(document.forms[0]); 

創建了 FormData 的實例后,可以將它直接傳給 XHR 的 send() 方法,如下所示:

 1 function submitData(){
 2   var xhr = createXHR();
 3   xhr.onreadystatechange = function(){
 4     if(xhr.readyState == 4){
 5       if((xhr.status >= 200 && xhr.status < 300) || xhr.status = 304){
 6         alert(xhr.responseText);
 7       }else{
 8         alert("Request was unsuccessful: " + xhr.status);
 9       }
10     }
11   };
12 
13   xhr.open("post","example.php",true);
14   var form=document.getElementById("user-info");
15   xhr.send(new FormData(form));
16 }

使用 FormData 的方便之處在於不必明確地在 XHR 對象上設置請求頭部。XHR 對象能夠識別傳入的數據類型是 FormData 的實例,並配置適當的頭部信息。

支持 FormData 的瀏覽器有 Firefox4+,Safari5+,Chrome和Android3+版WebKit。

跨域資源共享

通過 XHR 實現 Ajax 通信的一個主要限制,來源於跨域安全策略。

CORS(Cross-Origin Resource Sharing,跨域資源共享)背后的基本思想,及時使用自定義的HTTP頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功,還是應該失敗。

比如一個簡單地使用 GET 或 POST 發送的請求,它沒有自定義的頭部,而主題內容是 text/plain。在發送該請求時,需要給它附加一個額外的 Origin 頭部,其中包括請求頁面的源信息(協議、域名、端口),以便服務器根據這個頭部信息來決定是否給予響應,下面是 Oringin 頭部的一個示例:

Origin: http://www.nczonline.net 

如果服務器認為這個請求可以接受,就在 Access-Control-Allow-Origin 頭部中回發相同的源信息(如果是公共資源,可以回發 “*”)。例如:

Access-Control-Allow-Origin: http://www.nczonline.net 

如果沒有這個頭部,或者有這個頭部但源信息不匹配,瀏覽器就會駁回請求。正常情況下,瀏覽器會處理請求。注意,請求和響應都不包含 cookie 信息。

IE 對 CORS 的實現

微軟在 IE8 中引入了 XDR (XDomainRequest) 類型。這個對象與 XHR 類似,但能實現安全可靠的跨域通信。XDR 對象的安全機制部分實現了 W3C 的 CORS 規范。以下是 XDR 與 XHR 的一些不同之處。

  • cookie 不會隨請求發送,也不會隨響應返回。
  • 只能設置請求頭部信息的 Content-Type 字段。
  • 不能訪問響應頭部信息。
  • 只支持GET和POST請求。

所有的 XDR 請求都是異步執行的,不能用它來創建同步請求。請求返回之后,會觸發 load 事件,響應的數據也會保存在 responseText 屬性中。

在接收到響應后,你只能訪問響應的原始文本;沒有辦法確定響應的狀態代碼。而且,只要響應有效就會觸發 load 事件,如果失敗(包括響應中缺少 Access-Control-Allow-Origin頭部),就會觸發 error 事件。遺憾的是,除了錯誤本身之外,沒有其他信息可用,因此唯一能夠確定的就只有請求未成功了。要檢測錯誤,可以像下面這樣指定一個 onerror 事件處理程序。

1 var xdr=new XDomainRequest();
2 xdr.onload=function(){
3   alert(xdr.responseText);
4 };
5 xdr.onerror=function(){
6   alert("An erro occurred.");
7 };
8 xdr.open("get","http://www.somewhere-else.com/page");
9 xdr.send(null);

為支持 POST 請求,XDR 對象提供了 contentType 屬性,用來表示發送數據的格式,如下所示:

 1 var xdr=new XDomainRequest();
 2 xdr.onload=function(){
 3   alert(xdr.responseText);
 4 };
 5 xdr.onerror=function(){
 6   alert("An erro occurred.");
 7 };
 8 xdr.open("post","http://www.somewhere-else.com/page");
 9 xdr.contentType="application/x-www-form-urlencoded";
10 xdr.send("name1=value1&name2=value2");

 

這個屬性通過 XDR 對象影響頭部信息的唯一方式。

其他瀏覽器對 CORS 的實現

Forefox3.5+,Sarari4+,Chrome,iOS 版 Sarari 和 Android 平台中的 WebKit 都通過 XMLHttpRequest 對象實現了對 CORS 的原生支持。在嘗試打開不同來源的資源時,無需額外編寫代碼就可以出發這個行為。要請求位於另一個域中的資源,使用標准的 XHR 對象並在 open() 方法中傳入絕對 URL 即可,例如:

 1 var xhr=createXHR();
 2 xhr.onreadystatechange=function(){
 3   if(xhr.readyState == 4){
 4     if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
 5       alert(xhr.responseText);
 6     }else{
 7       alert("Request was unsuccessful: " + xhr.status);
 8     }
 9   }
10 };
11 
12 xhr.open("get","http://www.somewhere-else.com/page/",true);
13 xhr.send(null);

與 IE 中的 XDR 對象不同,通過跨域 XHR 對象可以訪問 status 和 statusText 屬性,而且還支持同步請求,跨域 XHR 對象也有一些限制,但為了安全,這些限制是必需的,一下就是這些限制。

  • 不能使用 setRequestHeader() 設置自定義頭部。
  • 不能發送和接收 cookie。
  • 調用 getAllResponseHeaders() 方法總會返回空字符串。

對於本地資源,最好使用相對 RUL,在訪問遠程資源時再使用絕對 URL。

Preflighted Requests

CORS 通過一種叫做 Preflighted Requests 的透明服務器驗證機制支持開發人員使用自定義的頭部,GET 或 POST 之外的方法,以及不同類型的主體內容,在使用下列高級選項來發送請求時,就會像服務器發送一個 Preflight 請求。這種請求使用 OPTIONS 方法,發送下列頭部。

  • Origin: 與簡單的請求相同。
  • Access-Control-Request-Method: 請求自身使用的方法。
  • Access-Control-Request-Headers: (可選) 自定義的頭部信息,多個頭部以逗號分隔。

以下是一個帶有自定義頭部的 NCZ 的使用 POST 方法發送的請求。

Origin: http://www.nczonline.net Access-Control-Request-Method: POST Access-Control-Request-Headers: NCZ 

發送這個請求后,服務器可以決定是否允許這種類型的請求。服務器通過在響應中發送如下頭部與瀏覽器進行溝通。

Access-Control-Allow-Origin: 與簡單的請求相同。
Access-Control-Allow-Method: 允許的方法,多個方法以逗號分隔。 Access-Control-Allow-Headers: 允許的頭部,多個頭部以逗號分隔。 Access-Control-Max-Age: 應該將這個 Preflight 請求緩存多長時間(以秒表示)。 

例如:

Access-Control-Allow-Origin: http://www.nczonline.net Access-Control-Allow-Method: GET,POST Access-Control-Allow-Headers: NCZ Access-Control-Max-Age: 1728000 

Preflight 請求結束后,結果將按照響應中指定的事件緩存起來。而為此付出的代價只是第一次發送這種請求時會多一次 HTTP 請求。

支持 Preflight 請求的瀏覽器包括 Firefox3.5+, Sarari4+ 和 Chrome。IE10 及更早版本都不支持。

帶憑據的請求(Requests with Credential)

默認情況下,跨域請求不提供憑據(Cookie、HTTP 認證及客戶端 SSL 證明等)。通過將 withCredentials 屬性設置為 true,可以指定某個請求應該發送憑據。如果服務器接收帶憑據的請求,會用下面的 HTTP 頭部來響應。

Access-Control-Allow-Credentials: true 

如果發送的是帶憑據的請求,單服務器的響應中沒有包含這個頭部,那么瀏覽器就不會把響應交給 JavaScript (於是,responseText 中將是空字符串,status 的值為0,而且會調用 onerror() 事件處理程序)。

支持 withCredentials 屬性的瀏覽器有 Firefox3.5+,Sarari4+ 和 Chrome。IE10 及更早版本都不支持。

下面這篇文章講的特別好,介紹了簡單地跨域請求、Preflight 請求和帶憑據的請求三種請求的區別和請求流程。 文章地址:http://www.cnblogs.com/loveis715/p/4592246.html

跨瀏覽器的 CORS (兼容性 CORS的寫法)

即使瀏覽器對 CORS 的支持程度並不都一樣,但所有瀏覽器都支持簡單地(非 Preflight 和不帶憑據的)請求,因此有必要實現一個跨瀏覽器的方案。檢測 XHR 是否支持 CORS 的最簡單的方式,就是檢查是否存在 withCredentials 屬性,再結合檢測 XDomainRequest 對象是否存在,就可以兼顧所有瀏覽器了。

 1 function createCORSRequest(method,url){
 2   var xhr=new XMLHttpRequest();
 3   if("withCredentials" in xhr){
 4     xhr.open(method,url,true);
 5   }else if(typeof XDomainRequest != "undefined"){
 6     xhr = new XDomainRequest();
 7     xhr.open(method,url);
 8   }else {
 9     xhr = null;
10   }
11   return xhr;
12 }
13 
14 var request = createCORSRequest("get","http://www.somewhere-else.com/page/");
15 if(request){
16   request.onload = function(){
17     //對request。responseText進行處理
18   };
19   request.send();
20 }

JSONP

JSONP 原理:JSONP 是通過動態script元素來使用的,使用時可以作為 src 屬性指定一個跨域 URL。 這里的script元素有能力不受限制地從其他域加載資源。因為 JSONP 是有效的 JavaScript 代碼,所以在請求完成后,即在 JSONP 響應加載到頁面中以后,就會立即執行。來看一個例子。

1 function handleResponse(response){
2   alert("you are at IP address "+ response.ip+", which is in "+response.city+", "+response.region_name);
3 }
4 
5 var script=document.createElement("script");
6 script.src="http://freegeoip.net/json/?callback=handleResponse";
7 document.body.insertBefore(script,document.body.firstChild);

下面這篇文章介紹了 JSON 和 JSONP,值得一看 文章地址:http://kb.cnblogs.com/page/139725/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM