---
# System prepended metadata

title: CORS

---

# CORS

## CORS (Cross-Origin Resource Sharing)

[參考系列文](https://blog.huli.tw/2021/02/19/cors-guide-1/) <= 幾乎從這看的三手整理資訊
[ref2](https://shubo.io/what-is-cors/)

### 理解
CORS (Cross-Origin Resource Sharing) 是針對不同源的請求而定的規範，透過 JavaScript 存取非同源資源時，server 必須明確告知瀏覽器允許何種請求，只有 server 允許的請求能夠被瀏覽器實際發送，否則會失敗。

瀏覽器的同源政策([Same-origin policy](https://developer.mozilla.org/zh-TW/docs/Web/Security/Same-origin_policy))，因為安全性問題的關係，只在瀏覽器這個執行環境(runtime)上才有的限制，實際上他擋的是回來的 response 而 requset 還是有發出去，server 還是有接收到請求

### 何謂同源
相同的　protocol + domain + port (協定 + 網域 + 埠號)

### 如何解決 CORS (簡單請求)

1. 關閉瀏覽器的安全性設置，進到瀏覽器內容更改目標輸入欄位加上 `--disable-web-security --user-data-dir=C:\Program Files (x86)\Google\Chrome\Application` 不過這只是自己電腦開發時有用的爛招
2. 如果跟想存取資源的後端有合作關係的話，請後端在 response header 加上 `Access-Control-Allow-Origin` 就可以了( * 允許任何 requset 存取)( * = wildcard )
3. proxy server，直接透或代理 server 來脫離瀏覽器的限制，讓 server 去請求資源，然後再回給瀏覽器，此時就可以自己在 server 加讓第二點的 header 來取得資源

總結就是根本上要在 reponse 加上第二點的 header，來允許發出 request 的 origin 能夠真的接收到 reponse

### 簡單請求與非簡單請求

兩者差別在非簡單請求會在真的發出 request 前先發一個預檢請求 `preflight request` ，在有 CORS 的情況下又有滿足以下條件時候會發生

* Request Method 非`GET` `POST` `HEAD` ( HEAD 跟 GET 很像差在沒有 response body)
* Content-Type 非 `text/plain` `multipart/form-data` `application/x-www-form-urlencoded`
* 有自訂 header (這我不太清楚是怎)

這個 preflight 的 Method 會是 `OPTIONS`，解決方式也是在後端加上 `Access-Control-Allow-Headers` 來允許某自定義的 header

簡單說，preflight 是個驗證機制，確保後端知道前端要送的 request 是預期的，瀏覽器才會放行。

### 帶上 cookie
如果要帶上 cookie 的話，那 `Access-Control-Allow-Origin` 不能是 *，一定要明確指定 origin。

需要在發送 request 的時候帶上 cookie，必須滿足三個條件：

1. 後端 Response header 有 `Access-Control-Allow-Credentials: true`
2. 後端 Response header 的 `Access-Control-Allow-Origin` 不能是 *，要明確指定
3. 前端 fetch 加上 `credentials: 'include'`

### 面試問答環節

Q : 為什麼要(會)有 CORS ?

A : 瀏覽器有同源政策，瀏覽器會擋你的跨來源請求，是因為安全性問題。

Q : 怎麼解決 CORS 問題 ?

A : 見 [簡單請求與非簡單請求](#簡單請求與非簡單請求)，算起來根本沒什麼前端的事情，就是發現 CORS 然後回報後端，但有個概念後才知道如何解決，大概就是在 req 跟 res 的 header 上做手腳這樣

Q : CORS 是擋 request 嗎 ?

A : 簡單請求的話不是，擋的是 response ; 非簡單請求的話是，這邊會先送一個 `preflight`，如果驗證沒過，則 request 不被送出