CORS 的介紹與實作

在介紹CORS 之前先討論一下什麼是同源政策

同源政策 (same origin policy)

意思就是兩個網頁有相同的domainprotocol以及port號,只要三者有一個不相同即為不同源。

不同源的舉例:

  • 從自己的網站向一個第三方 API 發出請求。
  • 從 CDN 載入一些網路資源,例如 CSS、JS、圖片等

現代瀏覽器基於安全性考量在你發出非同源的請求時,request 會發出,但是 response 會被瀏覽器擋下來,並且在瀏覽器的 console 裡可以看到錯誤訊息,例如下面這張圖:

same origin policy error

那要怎麼解呢?
只要依循 CORS 就可以了。
因為每當發起一個非同源的請求就會受到 CORS 的控制。

CORS 是什麼

cors (Cross Origin Resource Shraring) 就是 跨來源資源共用。

當你發起一個非同源的請求時, 被請求的 server 必須在 response 的 header 裡加上 Access-Control-Allow-Origin 的設定。
當瀏覽器收到 response 後,會查看 response 的 header,如果 header 上的 Access-Control-Allow-Origin 有出現發起請求的 origin ,瀏覽器就會解析 response,結果不會被擋下來。然後 header 大概會長下面這個樣子:

1
2
3
4
5
6
7
8
Content-Type: application/json
Content-Length: 250
Connection: keep-alive
Server: nginx
Access-Control-Allow-Origin: *
Cache-Control: no-cache, no-store, must-revalidate, private
Expires: 0
Pragma: no-cache

其中 Access-Control-Allow-Origin: * 表示任何來源都接受。
通常除非是公開的 API 服務,不然 server 上都會設定針對 origin 以及 http method 的限制。

Simple Request & Preflight Request

其實 CORS 又分為兩種情況,一種是簡單請求(simple request),另一種則是預檢請求(preflight request)。

simple request 的條件需同時滿足以下條件:

  • request method 為 GET、HEAD、POST 其一
  • Content-Type 為 application/x-www-form-urlencoded、multipart/form-data、text/plain 其一
  • 除了一些開放的 header,沒有指定 custom header

詳細的限制可以參考 MDN 簡單請求

反之,若是使用其他 HTTP method,如 DELETE 或是 PATCH 等,可能需要 server 驗證的情況,這時候會用到 preflight request。
假設我們要 DELETE 一筆資源,preflight request 會先發出一個 OPTION 的請求確認 server 是否接受該請求,如果接受才會發出真正的請求,如果不接受的話請求就會在這裡被中斷, DELETE 不會真的被送出。

結論

  • 對於非同源的請求,server 還是會接受請求並處理,但是同時 server 也要在 header 設定許可的 Access-Control-Allow-Origin ,瀏覽器才會解析請求結果,否則結果會被瀏覽器所擋下
  • simple request 只會有一次的請求
  • preflight request 會先發出一個 OPTION 請求,待 server 許可後 client 才會發出真正的請求,故會有兩次 request 發出

Reference

輕鬆理解 Ajax 與跨來源請求

跨來源資源共用(CORS)

伺服器端存取控制(CORS)

跨域資源共享CORS 詳解

How does Access-Control-Allow-Origin header work?

CORS for Developers