iT邦幫忙

2021 iThome 鐵人賽

DAY 22
0
Modern Web

前端藏寶圖系列 第 22

下有對策 - CORS

前言

雖然還沒實際碰過 CORS 錯誤,但實在太好奇了,所以到處看了文章,得出兩個感想:

  1. 查不到解法的時候就是要看規範了。CORS的規範:Fetch
  2. 需要由後端設定 Header 解決,前端則要了解基礎概念和知道為什麼會發生問題

因此這篇文章不會針對個別 CORS 錯誤該如何解決做討論,只會涵蓋什麼時候會踩到這個雷以及初步認識請求的類型。

什麼時候會遇到 CORS


圖片來源:MDN

以上圖為例:這個網頁的來源是http://domain-a.com,而網頁中的 canvas 要向http://domain-b.com請求資源,這種跨來源的請求就會受到 CORS 的管控。

CORS 機制提供網頁伺服器跨來源的存取控制,具體方法是透過 HTTP-header 的設定,讓網頁伺服器允許哪些來源可以存取它的資料

MDN 將請求類型分成三大類:簡單請求、預檢請求和帶有身份驗證(cookie)的請求,以下只先介紹前兩類

簡單請求

需要符合以下兩個條件才算簡單請求

  • 允許的請求方法:GETHEADPOST
  • 自定義的 Header 只允許以下幾種:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type 的內容只能是以下三種:
      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain
    • 請求中不能包含 ReadableStream 物件
    • 如果以 XMLHttpRequest物件發送請求,不能在此物件上註冊事件監聽器


圖片來源:JAVASCRIPT.INFO

對照上圖我們來看看一個跨來源的簡單請求會經歷哪些步驟:

  1. JavaScript 使用 fetch() 請求跨來源的資源
  2. 瀏覽器確認請求方法及 Header 後,向伺服器發送請求
  3. 伺服器回傳訊息和資源
  4. 瀏覽器確認回應中有包含Access-Control-Allow-Origin設有發送請求的來源*,允許JS讀取資料,換句話說,如果沒有設定就會發生CORS 錯誤

* 表示允許任何網域跨站存取資源

預檢請求

MDN有詳細列出哪些狀況會被歸類為預檢請求,我目前傾向記只要是非簡單請求都可以用預檢請求的步驟去思考。

以下也用圖示來理解預檢請求過程


圖片來源:JAVASCRIPT.INFO

  1. JavaScript 使用 fetch()
  2. 瀏覽器確認不是簡單請求,所以必須以OPTIONS方法向伺服器先發送訊息
  3. 伺服器確認來源和請求方法,如果通過,伺服器會傳送狀態碼200 OK資料告知瀏覽器可以發送HTTP請求
  4. 瀏覽器正式發送HTTP請求
  5. 伺服器確認請求來源,回傳資料
  6. 瀏覽器確認回應中的Access-Control-Allow-Origin是否包含請求來源*

Access-Control-XXX 的部分一開始看覺得很可怕,但只要專注在後面的文字就好,會發現就是在註記哪些來源,方法或資料格式是被允許的

小結:

  • 遇到 CORS 錯誤先區分發送的請求是屬於哪個類型
  • 可以觀察到無論是哪一種請求,都需要有 Access-Control-Allow-Origin 這個 Header,瀏覽器才會將資源給 JavaScript 取用

參考資料:
MDN
JAVASCRIPT.INFO
CORS 完全手冊
Deep Dive in CORS
CORS 是什麼? 如何設定 CORS?


上一篇
上有政策 - 同源政策
下一篇
來做一個鐵人賽倒數計時器吧!
系列文
前端藏寶圖30

尚未有邦友留言

立即登入留言