瀏覽器與伺服器通訊技術——跨域資源共享

snsart發表於2019-05-22

由於同源策略限制,預設情況下,使用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技術

 

相關文章