由於同源策略限制,預設情況下,使用XHR物件只能訪問與包含它的頁面位於同一個域(相同的協議、域名和埠)中的資源。要實現合理的跨域資源請求,有兩種策略:1.跨域資源共享 ,2.利用DOM中能夠執行跨域請求的功能。本文詳述了第一種策略的實現方法。
跨域資源共享(CORS)背後的基本思想,就是使用自定義的HTTP頭部讓瀏覽器與伺服器進行溝通,從而決定請求或相應是應該成功,還是應該失敗。這種方法需要修改伺服器程式碼。
一. 簡單請求的情況
如果只是簡單的使用GET或POST傳送請求,並且沒有自定義的頭部,且主體內容是text/plain。在傳送該請求時,需附加一個額外的origin頭部,其中包含請求頁面的源資訊(協議、域名和埠),伺服器會根據這個頭部資訊來決定是否給與響應。頭部例項如下:
origin:http://www.snsartme.com
大部分瀏覽器都通過XMLHttpRequest物件實現了CORS的原生支援。在訪問不同域的資源時,無需額外編寫程式碼就會自動傳送origin頭部。只需要在open()方法中傳入絕對URL即可,例如:
1 var xhr=new XMLHttpRequest(); 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("失敗"+xhr.responseText); 8 } 9 } 10 }; 11 12 xhr.open("get","http://www.somewhere.com/test.php",true); 13 xhr.send(null);
如果伺服器認為這個請求可以接受,就會在Access-Control-Allow-origin頭部中回發相同的源資訊(如果是公共資源,可以回發 ‘ * ’),比如在伺服器的php程式碼中加入以下程式碼,來傳送Access-Control-Allow-origin頭部:
header('Access-Control-Allow-origin:http:/www.snsartme.com');
簡單請求有如下一些限制:
1. 不能使用setRequestHeader()方法設定自定義頭部。
2. 不能傳送和接受cookie。
3. 呼叫getALLResponseHeaders()方法總會返回空字串。
二、 預檢請求
預檢請求(Preflighted Requests)必須首先使用OPTIONS方法發起一個預檢請求到伺服器,以獲知伺服器是否允許該實際請求。“預檢請求”的使用,可以避免跨域請求對伺服器的使用者資料產生無法預知的影響。OPTIONS方法發出的請求頭部如下:
Origin:與簡單的請求相同。
Access-Control-Request-Method:請求使用的方法
Access-Control-Request-Headers:自定義的頭部資訊,多個頭部以逗號分隔。
當使用setRequestHeader()方法設定了自定義頭部,或者請求方法不是get或post時,就會自動傳送預檢請求:
1 var xhr=new XMLHttpRequest(); 2 xhr.open("get","http://www.somewhere.com/test.php",true); 3 xhr.setRequestHeader("x-token", "I am x-token"); 4 xhr.send(null);
伺服器通過在響應中傳送如下頭部資訊與瀏覽器溝通,php程式碼如下:
1 header('Access-Control-Allow-origin:http://www.snsartme.com'); 2 header('Access-Control-Allow-Methods: GET,POST');//允許的方法 3 header('Access-Control-Allow-Headers:x-token'); //允許的頭部 4 header('Access-Control-Max-Age:7800'); //應該將預檢請求快取多長時間
三、帶憑據的請求
預設情況下,跨域請求不提供憑據(cookie,HTTP認證及客戶端SSL證明等)。通過將xhr的withCredentials屬性設定為true,可以指定某個請求應該傳送憑據。如果伺服器接送帶憑據的請求,會用下面的HTTP頭部來響應。
header('Access-Control-Allow-Credentials: true');
下一篇會詳解利用DOM中能夠執行跨域請求的功能實現跨域資源訪問,主要是jsonp技術