介紹
CORS (Cross-Origin Resource Sharing),中文為「跨來源資源共用」,主要出現在於網頁引用不同來源的資料時產生的錯誤。
當網頁使用 HTMLHttpRequest、Fetch、Axios 發起不是目前來源的請求時,會建立一個跨來源 HTTP 請求(cross-origin HTTP request),但基於同源政策 (same-origin policy) 的安全性考量,送出的跨來源 HTTP 請求會受到限制,進而出現 CORS 的錯誤。

Host、Referer、Origin 的區別
Host
此請求將送往哪裡,主要代表「域名+端口」。瀏覽器發起 HTTP 請求時會帶有此 HEADER。
Origin
從哪個網域傳送而出(跨域),主要由「協議+域名+端口」。用於 CORS 請求、同域的「POST」。
Referer
來自哪個網域,主要由「協議+域名+端口+路徑+參數」。當前請求的來源頁面的地址,服務端一般使用 Referer 首部作為訪問來源,以此進行「統計分析」、「日誌紀錄」、「暫存優化」等。
一般情况下瀏覽器會帶此 HEADER,但下列情況不會帶有
- 來源頁面協議為 File 或 Data URI(例如:頁面從本地打開的)
- 來源頁面是 HTTPS,而目標 URL 是 HTTP
- 瀏覽器地址欄直接輸入網址訪問
- 通过瀏覽器書籤直接訪問
- 使用 JS 的 location.href 跳轉
Origin 與 Referer 比較
- 只有「跨域请求」、「同域發送 POST」請求時,才會攜帶 origin;而 Referer只要能被瀏覽器獲取都會攜帶,除了上面的情況外
- 若瀏覽器不能獲取請求源頁面網址,Referer 不會放入 HEADER 中,但 Origin 依舊會發送,但值是 null 而已(註:雖值為 null,但此請求依舊屬於 CORS 請求)
- Origin 的值只包括**「協議」、「域名」、「端口」,而 Rerferer 不但包括「協議」、「域名」、「端口」、「路徑」、「參數」,但**不包括 hash 值
CORS 預檢(簡單請求)
在發起跨來源資源共用的請求時,通常會發起 CORS 預檢 來驗證是否能夠取得相關資源,若是無法取得,就會避免正式請求的發起,以避免資源的浪費。
部分不受同源政策限制的情況
- 跨來源寫入
- 鏈結 <a>
- 重新導向
- 表單提交
- 嵌入
- <script> 嵌入腳本
- <link rel=”stylesheet” href=“…”> 嵌入 CSS
- <img> <video> <audio> 等等嵌入資源
- 通過 <iframe> 載入資源
⛔ 一般而言,跨域讀取是不被允許的。包括讀取 request 中的 res
如何允許不同源的網站訪問
跨域讀操作一般是不被允许的,而這種情况是我们開發過程中最關心、最常見的情況,因此必須解决。可以使用 CORS 來允許跨域訪問。CORS 是 HTTP 的一部分,它允許伺服器指定那些主機可以從這個伺服器加載資料。
若想實現 CORS 機制的跨域請求,是需要瀏覽器與伺服器同時支援。關於瀏覽器對 CORS 的支援情況,再加上 CORS 整個過程都是由瀏覽器自動完成的,因此前端無需做任何設置。
為何需要 CORS 跨域訪問
随著 Web 開放的程度越來越高,頁面的內容也越來越豐富。為了分而治之,頁面中的内容可能來自不同地方,因此必然會通過 API 進行跨域訪問。CORS(Cross-Origin Resource Sharing)由 W3C 於 2009/03/17 編寫工作草案,直到 2014/01/16 才正式成为行業規範,所有瀏覽器得以遵守。
CORS 工作原理
- 若瀏覽器發送跨域請求,HTTP 請求的 HEADER 就會攜帶 Origin 表明自己的位置
- 伺服器收到請求後,就可以根據傳過來的 Origin 值做邏輯判斷,決定是否要共享資源給此網站。這個決定將透過 Res HEADER 的「**Access-Control-Allow-Origin」**來乘載,它的 value 可以是任意值,如下情况:
- 值為「*」通配符,允许所有的 Origin 共享此資源
- 值與 Origin「相同」,則共享给此 Origin
- 值與 Origin「不相同」,則不共享给此 Origin
- 無此標頭,則不共享给此 Origin
- 瀏覽器收到 Response 後,會去提取「Access-Control-Allow-Origin」的值,然後根據上述的規則來決定是否要接收此響應的內容
CORS 細微操控(授權響應 HEADER)
在 CORS 規範中,除了可以通过「**Access-Control-Allow-Origin」**響應頭來對主體資源(URL)進行授權外,還提供了針對具體響應頭更精細的控制,這個 Res 的 HEADER 就是「Access-Control-Expose-Headers」。換句話講,該值用於規定那些 Res HEADER 可以暴露給前端,預設情況下以下 6 種 Res HEADER 無需特別的顯示指定就會支持:
- Cache-Control
- Content-Language
- Content-Type
- Expires
- Last-Modified
- Pragma
若不在此值裡面的頭,則瀏覽器讓其對前端不可見,對 JavaScript 也不可見。
但是,這種精細控制 HEADER 的機制對於簡單請求是無效的,只針對非簡單請求(複雜請求)。由此可見,將哪些類型的跨域資源請求劃分為簡單請求的範疇就特別重要。