Javascript Ajax總結——跨域資源共享

XHR對象只能訪問與包含它的頁面位於同一個中的資源。這種安全策略能夠預防某些惡意行爲。
CORS(Cross-Origin Resource Sharing,跨域資源共享)是W3C的一個工做草案,定義了在必須訪問跨域資源時,瀏覽器與服務器應該如何溝通。CORS基本思想:使用自定義的HTTP頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功仍是失敗。
如:一個使用GET或POST發送的請求,沒有自定義的頭部,主體內容是text/plain。發送請求時,須要給它附加一個額外的Origin頭部,其中包含請求頁面的源信息(協議、域名和端口),以便服務器根據這個頭部信息來決定是否給與響應。

Origin頭部如:
Origin: http://www.nczonline.net
若服務器認爲這個請求能夠接受,就在Access-Control-Allow-Origin頭部中回發相同的源信息(如果公共資源,能夠回發「*」)。如:
Access-Control-Allow-Origin: http://www.nczonline.net
若沒有這個頭部,或有這個頭部但源信息不匹配,瀏覽器就會駁回請求。正常狀況下,瀏覽器會處理請求。
注:請求和響應都不包含cookie信息。

一、IE對CORS的實現
微軟在IE8中引入了XDR(XDomainRequest)類型,可以實現安全可靠的跨域通訊。XDR對象的安全機制部分實現了W3C的CORS規範。
XDR與XHR的一些不一樣之處
* cookie不會隨請求發送,也不會隨響應返回。
* 只能設置請求頭部信息中的Content-Type字段。
* 不能訪問響應頭部信息。
* 只支持GET和POST請求。
被請求的資源能夠根據它認爲合適的任意數據(用戶代理、來源頁面等)來決定是否設置Access-Control-Allow-Origin頭部。做爲請求的一部分,Origin頭部的值表示請求的來源域,以便遠程資源明確的識別XDR請求。
XDR對象的使用方法與XHR對象很是類似。也是建立一個XDomainRequest的實例,調用open()方法,再調用send()方法。但與XHR對象的open()方法不一樣,XDR對象的open()只接收2個參數:請求的類型和URL。
全部XDR請求都是異步執行的。請求返回以後,會觸發load事件,響應的數據也會保存在responseText屬性中,如:
var xdr = new XDomainRequest();
xdr.onload = function(){
    alert(xdr.responseText);
};
xdr.open("get", "http://www.somewhere-else.com/page/");
xdr.send(null);

在接收到響應後,只能訪問響應的原始文件,沒有辦法肯定響應的狀態代碼。並且只要響應有效就會觸發load事件,若是失敗就會觸發error事件。遺憾的是,除了錯誤自己以外,沒有其餘信息可用,所以惟一可以肯定的就只有請求未成功了。要檢測錯誤,能夠指定一個onerror事件處理程序:
var xdr = new XDomainRequest();
xdr.onload = function(){
    alert(xdr.responseText);
};
xdr.onerror = function(){
    alert("An error occurred.");
};
xdr.open("get", "http://www.somewhere-else.com/page/");
xdr.send(null);

注:致使XDR請求失敗的因素不少,因此建議經過onerror事件處理程序來捕獲該事件;不然,即便請求失敗也不會有任何提示。

在請求返回前調用abort()方法能夠終止請求:
xdr.abort(); //終止請求
XDR對象也支持timeout屬性以及ontimeout事件處理程序。如:
var xdr = new XDomainRequest();
xdr.onload = function(){
    alert(xdr.responseText);
};
xdr.onerror = function(){
    alert("An error occurred.");
};
xdr.timeout = 1000;
xdr.ontimeout = function(){
    alert("Request took too long.");
};
xdr.open("get", "http://www.somewhere-else.com/page/");
xdr.send(null);
運行1s後超時,並隨機調用ontimeout事件處理程序。

爲支持POST請求,XDR對象提供了contentType屬性,用來表示發送數據的格式,如:
 1   var xdr = new XDomainRequest();
 2     xdr.onload = function(){
 3         alert(xdr.responseText);
 4     };
 5     xdr.onerror = function(){
 6         alert("An error 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的實現

 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 //跨域請求的url爲絕對的連接
12 xhr.open("get", "http://www.somewhere-else.com/page/", true);
13 xhr.send(null);
限制:
* 不能使用setRequestHeader()設置自定義頭部。
* 不能發送和接收cookie。
* 調用getAllResponseHeaders()方法總會返回空字符串。

對於本地資源,最好使用相對URL,訪問遠程資源時使用絕對URL,能夠消除歧義,避免出現限制訪問頭部或本地cookie信息等問題。
三、跨瀏覽器的CORS
全部瀏覽器都支持簡單的(非Preflight和不帶憑據的)請求,所以有必要實現一個跨瀏覽器的方案。

 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 var request = cresteCORSRequest("get", "http://www.somewhere-else.com/page/");
14 if(request){
15     request.onload = function(){
16         //對request.responseText進行處理
17     };
18     request.send();
19 }
Firefox、Safari、Chrome中的XMLHttpRequest對象與IE中的XDomainRequest對象相似,都提供了夠用的接口,所以以上模式仍是至關有用的。
這兩個對象共同的屬性/方法以下: * abort():用於中止正在進行的請求。 * onerror:用於替代onreadystatechange檢測錯誤。 * onload:用於替代onreadystatechange檢測成功。 * responseText:用於取得相應內容。 * send():用於發送請求。以上成員都包含在createCORSRequest()函數返回的對象中,在全部瀏覽器中都能正常使用。
相關文章
相關標籤/搜索