本人是一個應屆生,面試的時候常常會被問到跨域的問題,CORS固然也是解決跨域的方法之一了。可是當面試官繼續問:「CORS跨域是怎麼實現的?爲何會有OPTIONS請求呢?OPTIONS請求有什麼用途呢?」可能回答的就不是那麼完美。html
因此,就總結概括瞭如下關於CORS的詳細知識。。。面試
參考文章:
跨域資源共享CORS詳解
爲何會有OPTIONS請求
瀏覽器同源策略及其規避方法
HTTP訪問控制(CORS)json
CORS
是W3C標準,全稱「跨域資源共享(Corss-orign resource sharing)」。後端
它容許瀏覽器向跨源服務器發送XMLHttpRequest
請求,從而克服了AJAX
只能同源使用的限制。api
CORS
須要瀏覽器和服務器同時支持;整個CORS
的通訊過程都是瀏覽器自動完成的,用戶不須要參與;CROS
通訊和同源的AJAX
通訊無差異;瀏覽器檢測到AJAX
請求跨源時會自動添加一些附加的頭信息有時候還會多一次附加請求,可是用戶不會有感受。跨域
CORS
通訊的關鍵仍是服務器,只要服務器實現了CORS
的接口,就能夠跨源通訊。瀏覽器
CORS請求分爲兩大類:簡單請求和非簡單請求,瀏覽器對這兩種請求的處理是不同的。安全
知足如下條件就是簡單請求:bash
GET
,POST
,HEAD
對於簡單請求,瀏覽器會直接發出CORS
請求;瀏覽器發現這次跨源的AJAX
請求是簡單請求,就自動在請求頭信息中添加Origin
字段來講明本次請求來自哪一個源(域名+端口+協議);服務器根據這個值來決定是否贊成此次請求。服務器
若是Origin
指定的源不在許可的範圍內:
服務器會返回一個正常的HTTP響應,可是這個響應的頭信息沒有包含Access-Control-Allow-Origin
字段,會拋出錯誤,被XMLHttpRequest
的onerror
回調函數捕獲(!!這種狀況狀態碼沒法識別,返回的極可能是200
)。
若是Origin
指定的源在許可的範圍內:
服務器返回的響應會多幾個字段:
cookie
;默認狀況下,cookie
不包含在CORS
請求中。該字段設爲true
時,表示服務器許可,cookie
能夠包含在請求中,一塊兒發送給服務器。CORS
請求時,XMLHttpRequest
對象的getResponseHeader()
只能拿到6個基本字段,Cache-Control
,Content-Language
,Content-Type
,Expires
,Last-Modified
,Pragma
。若是想拿到其餘字段就要在Access-Control-Expose-Headers
中指定,getResponseHeader('FooBar')
,就能夠返回FooBar
的值。上面說到CORS
請求默認不會發送cookie
和HTTP
的認證信息,因此要把cookie
發送到服務器不但要服務器贊成設置
Access-Control-Allow-Credentials:true
複製代碼
還要開發者在AJAX請求中設置withCredentials
屬性
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
複製代碼
不然,即便服務器贊成發送cookie
,瀏覽器也不會發送。 !!!若是要發送cookie
,那麼Access-Control-Allow-Origin
的值不能是*
,必須是指定明確的,與請求網頁一致的域名;同時,cookie
依然遵循同源策略,只有用服務器域名設置的cookie
纔會上傳,其餘域名的cookie
不會上傳,且(跨源)原網頁代碼中document.cookie
也沒法讀取服務器域名下的cookie
。
當知足下面任意條件時,會發送預檢請求:
非簡單請求的CORS
請求,會在正式通訊以前,增長一次HTTP
查詢請求(‘預檢’請求)。preflighted requests
是CORS
中一種透明的服務器驗證機制。預檢請求首先會向另外一個域名資源發送HTTP
OPTIONS
請求頭,來驗證發送的請求是否安全。
瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器許可的名單之中,以及可使用哪些HTTP
動詞和頭信息字段。只有獲得確定的答覆,瀏覽器纔會發出正式的XMLHttpRequest
請求,不然會報錯。
瀏覽器發現,是一個非簡單請求,就自動發送一個「預檢」請求,要求服務器確認。
預檢請求的請求方法是OPTIONS
,表示詢問;頭信息裏的關鍵字是Origin
,表示請求來自哪一個源除了Origin
還有兩個字段:
OPTIONS請求的用途?
一、獲取服務器支持的HTTP請求方法。
二、用來檢查服務器的性能。
AJAX進行跨域請求時的預檢,須要向另外一個域名的資源發送一個HTTP OPTIONS的請求頭,
用以判斷實際的請求是否安全。(這個是瀏覽器加上的,後端沒有作任何操做)
複製代碼
爲何會有OPTIONS請求?
規範要求,對那些可能對服務器數據產生反作用的HTTP
請求方法(特別是GET
之外的HTTP
請求,或搭配某些MIME
類型的POST
請求),瀏覽器必須首先使用OPTIONS
發送一個預檢請求,來獲取服務器是否容許該跨域請求。服務器確認容許跨域後,瀏覽器再發送實際的HTTP
請求。
爲何沒有發生預檢請求?
在跨域請求服務器時,設置了Content-Type
爲application/json
,後,按理說,應該是會發起預檢請求。可實際結果與理論發生了衝突。
緣由在於:預檢請求須要在服務器中進行配置,在修改該路由的代碼爲如下內容後,瀏覽器正確地發起了OPTIONS預檢請求。
const cors=require('cors');
router.options('/api/test/corsopt',cors());
router.post('/api/test/corsopt',cors(),(req,res)=>{
res.end('test');
})
複製代碼
服務器接受了預檢請求之後,會檢查Origin
,Access-Control-Request-Methods
,Access-Control-Request-Headers
字段之後,確認容許跨域請求,就會作出迴應。
若是瀏覽器否認了預檢請求,會返回一個正常的HTTP響應,可是沒有任何CORS相關的頭信息字段。這時瀏覽器就會認爲服務器不一樣意預檢請求,所以觸發一個錯誤,被XMLHttpRequest
對象的onerror
函數捕獲。該錯誤信息爲:
XMLHttpRequest cannot load http://xxx.xxx.com.
Origin http://xxx.xxx.com is not allowed by Access-Control-Allow-Origin.
複製代碼
服務器響應的其餘CORS相關字段:
一旦服務器經過了「預檢」請求,之後每次瀏覽器正常的CORS請求,都和簡單請求同樣,會有一個Origin
頭信息字段;服務器響應也是同樣會有一個Access-Control-Allow-Origin
頭信息字段。