CORS跨域原理

我們都知道由于同源策略的存在,導(dǎo)致我們在跨域請求數(shù)據(jù)的時候非常的麻煩

首先阻擋我們的所謂"同源"到底是什么呢?

所謂同源就是瀏覽器的一個安全機制,不同源的客戶端腳本沒有在明確授權(quán)的情況下,不能讀寫對方資源。

由于存在同源策略的限制,而又有需要跨域的業(yè)務(wù),所以就有啦CORS的出現(xiàn)

我們都知道,jsonp也可以跨域,那為什么還要使用CORS呢

  1. jsonp只可以使用 GET 方式提交
  2. 不好調(diào)試,在調(diào)用失敗的時候不會返回任何狀態(tài)碼
  3. 安全性,萬一假如提供jsonp的服務(wù)存在頁面注入漏洞,即它返回的javascript的內(nèi)容被人控制的。那么結(jié)果是什么?所有調(diào)用這個 jsonp的網(wǎng)站都會存在漏洞。于是無法把危險控制在一個域名下…所以在使用jsonp的時候必須要保證使用的jsonp服務(wù)必須是安全可信的。

開始CORS

CORS 是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing),他允許瀏覽器向跨源服務(wù)器發(fā)送XMLHttpRequest請求,從而克服啦 AJAX 只能同源使用的限制

CORS 需要瀏覽器和服務(wù)器同時支持,整個 CORS通信過程,都是瀏覽器自動完成不需要用戶參與,對于開發(fā)者來說,CORS的代碼和正常的 ajax 沒有什么差別,瀏覽器一旦發(fā)現(xiàn)跨域請求,就會添加一些附加的頭信息,

CORS這么好嗎,難道就沒有缺點嘛?

答案肯定是NO,目前所有最新瀏覽器都支持該功能,但是萬惡的IE不能低于10

簡單請求和非簡單請求

瀏覽器將CORS請求分成兩類:簡單請求和非簡單請求

1. 請求方法是以下三種方法之一:
- HEAD
- GET
- POST
1. HTTP的頭信息不超出以下幾種字段
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于三個值 `application/x-www-form-urlencoded`、`multipart/form-data`、`text/plain`

凡是同時滿足上面兩種情況的就是簡單請求,反之則非簡單請求,瀏覽器對這兩種請求的處理不一樣

簡單請求

對于簡單請求來說,瀏覽器之間發(fā)送CORS請求,具體來說就是在頭信息中,增加一個origin字段

來看下例子:

GET /cors? HTTP/1.1
Host: localhost:2333
Connection: keep-alive
Origin: http://localhost:2332
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
Accept: */*
Referer: http://localhost:2332/CORS.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
If-None-Match: W/"1-NWoZK3kTsExUV00Ywo1G5jlUKKs"

上面的頭信息中,Origin字段用來說名本次請求來自哪個源,服務(wù)器根據(jù)這個值,決定是否同意這次請求.

如果Origin指定的源不在允許范圍之內(nèi),服務(wù)器就會返回一個正常的HTTP回應(yīng),然后瀏覽器發(fā)現(xiàn)頭信息中沒有包含Access-Control-Allow-Origin 字段,就知道出錯啦,然后拋出錯誤,反之則會出現(xiàn)這個字段(實例如下)

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
  1. Access-Control-Allow-Origin 這個字段是必須的,表示接受那些域名的請求(*為所有)
  2. Access-Control-Allow-Credentials 該字段可選, 表示是否可以發(fā)送cookie
  3. Access-Control-Expose-Headers 該字段可選,XHMHttpRequest對象的方法只能夠拿到六種字段: Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma ,如果想拿到其他的需要使用該字段指定。

如果你想要連帶Cookie一起發(fā)送,是需要服務(wù)端和客戶端配合的

// 服務(wù)端
Access-Control-Allow-Credentials: true
// 客戶端
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
// 但是如果省略withCredentials屬性的設(shè)置,有的瀏覽器還是會發(fā)送cookie的
xhr.withCredentials = false;

非簡單請求

非簡單請求則是不滿足上邊的兩種情況之一,比如請求的方式為 PUT,或者請求頭包含其他的字段

非簡單請求的CORS請求是會在正式通信之前進行一次預(yù)檢請求

瀏覽器先詢問服務(wù)器,當前網(wǎng)頁所在的域名是否可以請求您的服務(wù)器,以及可以使用那些HTTP動詞和頭信息,只有得到正確的答復(fù),才會進行正式的請求

// 前端代碼
var url = 'http://localhost:2333/cors';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();

由于上面的代碼使用的是 PUT 方法,并且發(fā)送啦一個自定義頭信息.所以是一個非簡單請求,當瀏覽器發(fā)現(xiàn)這是一個非簡單請求的時候,會自動發(fā)出預(yù)檢請求,看看服務(wù)器可不可以接收這種請求,下面是"預(yù)檢"的 HTTP 頭信息

OPTIONS /cors HTTP/1.1
Origin: localhost:2333
Access-Control-Request-Method: PUT // 表示使用的什么HTTP請求方法
Access-Control-Request-Headers: X-Custom-Header // 表示瀏覽器發(fā)送的自定義字段
Host: localhost:2332
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
User-Agent: Mozilla/5.0...

"預(yù)檢"使用的請求方法是 OPTIONS , 表示這個請求使用來詢問的,

預(yù)檢請求后的回應(yīng)

服務(wù)器收到"預(yù)檢"請求以后,檢查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,確認允許跨源請求,就可以做出回應(yīng)

預(yù)檢的響應(yīng)頭:

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://localhost:2332 // 表示http://localhost:2332可以訪問數(shù)據(jù)
Access-Control-Allow-Methods: GET, POST, PUT      
Access-Control-Allow-Headers: X-Custom-Header    
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

如果瀏覽器否定啦"預(yù)檢"請求,會返回一個正常的HTTP回應(yīng),但是沒有任何CORS的頭相關(guān)信息,這是瀏覽器就認定,服務(wù)器不允許此次訪問,從而拋出錯誤

預(yù)檢之后的請求

當預(yù)檢請求通過之后發(fā)出正經(jīng)的HTTP請求,還有一個就是一旦通過啦預(yù)檢請求就會,請求的時候就會跟簡單請求,會有一個Origin頭信息字段。

通過預(yù)檢之后的,瀏覽器發(fā)出發(fā)請求

PUT /cors HTTP/1.1
Origin: http://api.bob.com // 通過預(yù)檢之后的請求,會自動帶上Origin字段
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容