默認狀況下,爲預防某些而已行爲,瀏覽器的XHR對象只能訪問來源於同一個域中的資源。可是咱們在平常實際開發中,經常會遇到跨域請求的需求,所以就出現了一種跨域請求的方案:CORS(Cross-Origin Resource Sharing)跨域資源共享。
CORS背後的原理是:使用自定的HTTP頭部與服務器進行溝通,從而由服務器決定響應是否成功。api
使用CORS須要客戶端和服務端二者配合。跨域
目前在大多數瀏覽器下(CORS在各瀏覽器下支持狀況),都原生支持CORS,代碼編寫時和同域的請求差很少,只須要在xhr.open()的時候傳入絕對URL便可。例如:瀏覽器
var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if(xhr.readyState == 4){ if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ console.log(xhr.responseText) }else { console.log('err' + xhr.status); } } }; xhr.open('get','http://www.xxx.com/api/something/',true); xhr.send(null);
這樣就能夠發送一個跨域請求了,可是若是隻是如上面示例代碼同樣發送的話會報錯,由於服務器並未設置容許咱們這個請求,所以CORS還須要服務端來配合。緩存
服務器只須要在響應頭部中設置Access-Control-Allow-Origin便可讓客戶端訪問。安全
假設客戶端的域名是http://www.xxx.com,那麼服務端只要在Access-Control-Allow-Origin的設置中含有http://www.xxx.com,那麼這個CORS請求便可成功。若是Access-Control-Allow-Origin設置爲*,那麼任意域名均可以訪問這個服務端,可是爲了安全起見,通常並不建議這樣作。服務器
如下截圖是一個CORS請求後服務端正常返回的示例:併發
CORS還有一種叫作Preflighted Request(預飛請求)的透明服務器驗證機制完成請求過程,若是你在請求的時候使用了表1中的選項來發送請求(使用setRequestheaders設定自定義頭部),那麼就會觸發Preflighted Request,它的請求過程以下:cors
1.XHR對象send發出請求url
2.瀏覽器先向服務端發出一個OPTIONS方法的請求,併發送下列頭部:code
請求頭部信息 | 含義 |
---|---|
Origin | 來源域名,與簡單的請求相同。 |
Access-Control-Request-Method | 請求自身使用的方法。 |
Access-Control-Request-Headers (可選) | 自定義的頭部信息,多個頭部以逗號分隔。 |
OPTIONS請求示例:
客戶端請求的代碼(比上面多加了個header):
var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if(xhr.readyState == 4){ if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ console.log(xhr.responseText) }else { console.log('err' + xhr.status); } } }; xhr.open('get','http://www.xxx.com/api/poisearch/',true); xhr.setRequestHeader('haha',1); xhr.send(null);
請求結果(這裏OPTIONS請求觸發了,但沒有找到這個url):
3.服務器接收到這個請求後,根據上面的頭部信息判斷是否予以接收。並在響應中發送以下頭部與瀏覽器進行溝通:
響應頭部信息 | 含義 |
---|---|
Access-Control-Allow-Origin | 來源域名,與簡單的請求相同。 |
Access-Control-Allow-Methods | 容許的方法,多個方法以逗號分隔。 |
Access-Control-Allow-Headers(可選) | 容許的頭部,多個頭部以逗號分隔。 |
Access-Control-Max-Age | 應該將這個Preflight請求緩存多長時間(以秒錶示) |
4.Preflighted Request結束後,結果將按照指定的時間緩存起來。
5.若是服務端判斷上面設置的額外信息能夠容許請求,那麼就會再請求一次正常的請求了。