跨源資源共享(CORS)
跨源資源共享(CORS)是W3C工作草案,它定義了浏覽器和伺服器在跨源通路源時必須如何通信。CORS背後的基本思想是使用自定義HTTP頭來允許浏覽器和伺服器充分了解對方以确定請求或響應是成功還是失敗。
對于一個簡單的請求,一個使用GET或POST但沒有自定義标頭且其正文
text/plain
的請求會被發送一個額外的标頭
Origin
。該
Origin
頭包含請求頁面的來源(協定,域名,端口),使伺服器可以很容易地确定它是否應該成為一個響應。示例
Origin
頭可能如下所示:
Origin: http://www.nczonline.net
如果伺服器決定允許該請求,它将發送一個
Access-Control-Allow-Origin
标題回顯與發送的相同的源,或者如果它是公共資源,則發送“*”。例如:
Access-Control-Allow-Origin: http://www.nczonline.net
如果此标題丢失或者來源不比對,則浏覽器将禁止該請求。如果一切正常,則浏覽器處理請求。請注意,請求和響應都不包含Cookie資訊。
所有前面提到的浏覽器都支援這些簡單的請求。Firefox 3.5+,Safari 4+和Chrome全都支援通過
XMLHttpRequest
對象使用。當試圖打開不同來源的資源時,會自動觸發此行為,而無需任何額外的代碼。例如:
var xhr = new XMLHttpRequest();
xhr.open("get", "http://www.nczonline.net/some_resource/", true);
xhr.onload = function(){ //instead of onreadystatechange
//do something
};
xhr.send(null);
要在Internet Explorer 8中執行相同的操作,您需要以相同的方式使用該
XDomainRequest
對象:
var xdr = new XDomainRequest();
xdr.open("get", "http://www.nczonline.net/some_resource/");
xdr.onload = function(){
//do something
};
xdr.send();
Mozilla團隊在他們的文章中建議您應該檢查CORS是否存在,
withCredentials
以确定浏覽器是否通過XHR支援CORS。然後,您可以結合該
XDomainRequest
對象的存在來涵蓋所有浏覽器:
function createCORSRequest(method, url){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr){
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined"){
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
xhr = null;
}
return xhr;
}
var request = createCORSRequest("get", "http://www.nczonline.net/");
if (request){
request.onload = function(){
//do something with request.responseText
};
request.send();
}
将
XMLHttpRequest
在Firefox,Safari和Chrome浏覽對象有類似足夠的接口的IE
XDomainRequest
對象,這種模式運作相當好。通用接口屬性/方法是:
-
- 用于停止正在進行的請求。abort()
-
- 使用而不是onerror
檢測錯誤。onreadystatechange
-
- 使用而不是onload
檢測成功。onreadystatechange
-
- 用于擷取響應的内容。responseText
-
- 用于發送請求。send()
預先請求的請求
CORS允許使用自定義标題,GET或POST以外的方法以及不同的主體内容類型,通過伺服器驗證的透明機制稱為preflighted請求。當您嘗試使用其中一個進階選項送出請求時,會向伺服器發出“預檢”請求。該請求使用OPTIONS方法并發送以下标題:
-
- 和簡單的請求一樣。Origin
-
- 請求想要使用的方法。Access-Control-Request-Method
-
- (可選)用逗号分隔的自定義标題清單。Access-Control-Request-Headers
假設使用自定義标頭的POST請求的示例名為
NCZ
:
Origin: http://www.nczonline.net
Access-Control-Request-Method: POST
Access-Control-Request-Headers: NCZ
在這個請求期間,伺服器可以确定它是否允許這種類型的請求。伺服器通過在響應中發送以下标題将其傳遞給浏覽器:
-
- 和簡單的請求一樣。Access-Control-Allow-Origin
-
- 逗号分隔的允許方法清單。Access-Control-Allow-Methods
-
- 伺服器允許的逗号分隔的标題清單。Access-Control-Allow-Headers
-
- 此預檢請求應緩存的時間量(以秒為機關)。Access-Control-Max-Age
例:
Access-Control-Allow-Origin: http://www.nczonline.net
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: NCZ
Access-Control-Max-Age: 1728000
一旦預檢請求完成,結果會在響應中指定的時間段内被緩存; 在第一次建立這種類型的請求時,您隻會承擔額外HTTP請求的成本。
Firefox 3.5+,Safari 4+和Chrome全都支援預沖的請求; Internet Explorer 8沒有。
認證請求
預設情況下,跨源請求不提供憑據(Cookie,HTTP身份驗證和用戶端SSL證書)。您可以通過将該
withCredentials
屬性設定為true 來指定請求應發送憑據。如果伺服器允許憑證請求,則它使用以下HTTP頭進行響應:
Access-Control-Allow-Credentials: true
如果發送了憑證請求并且該頭不作為響應的一部分發送,那麼浏覽器不會将響應傳遞給JavaScript(
responseText
是一個空字元串,
status
為0,并且
onerror()
被調用)。請注意,伺服器也可以發送此HTTP标頭作為預檢響應的一部分,以訓示允許源發送憑證請求。
Internet Explorer 8不支援該
withCredentials
屬性; Firefox 3.5,Safari 4和Chrome都支援它。