The Issue of the Day Before

設定 crossorigin=anonymous 反而出錯

http -

可以下任一方法處理,

  • 拿掉 script 標籤中的 crossorigin=anonymous

  • 在伺服器的回應中加入標頭 access-control-allow-origin: *

Why

為了安全, HTTP 多了一個叫 Cross-Origin Resource Sharing (跨來源資源共用) 簡稱 CORS 的東西。 而基於安全考量,程式碼所發出的跨來源 HTTP 請求會受到限制。不管你是使用 XMLHttpRequest 及 Fetch 或其他利用這些物件的函式庫來取得資源。 這些程式都遵守同源政策(same-origin policy)。這代表除非使用符合的 CORS 標頭,否則就只能請求與其相同來源的 HTTP 資源。

What

origin

origin 網域(domain) [+ 通訊協定(protocol) [+ 通訊埠(port)]]

CORS

CORS CORS 是一種藉由附加額外的 HTTP 標頭使瀏覽器能取得其他網域伺服器資源的機制。 當瀏覽器請求一個不是目前文件來源(origin),例如是來自於不同網域(domain)、通訊協定(protocol)或通訊埠(port)的資源時,會建立一個跨來源 HTTP 請求(cross-origin HTTP request)。

crossorigin

Cross Origin 對<audio>、<img>、<link>、<script> 和 <video> 等標籤設定 CORS 。

How

crossorigin 有三個可選值

  • anonymous 設定 modeCORS,不發送`user credentials`,並設定 credentials modesame-origin

e.q.
const res = await fetch("https://pie.dev/get", {
  method: "GET",
  mode: 'cors',
  credentials: "same-origin"
});
  • use-credentials 設定 modeCORS 發送`user credentials`,設定 credentials modeinclude

e.q.
const res = await fetch("https://pie.dev/get", {
  method: "GET",
  mode: 'cors',
  credentials: "include"
});
  • "" 等同 anonymous。

其他不在三者的值都算 anonymous。

而其沒有 crossorigin 屬性則是內定為是 No CORS

e.q.
const res = await fetch("https://pie.dev/get", {
  method: "GET",
  mode: 'no-cors',
});

user credentials (用戶憑據)包含項目

  • cookie

  • 客戶端 SSL 證書

  • HTTP 身份驗證

credentials mode

  • omit 在請求中排除用戶憑據,回傳任何用戶憑據都會被忽略。

  • same-origin 在對同源 URL 的請求中包含用戶憑據,並使用從同源 URL 的回應的用戶憑據。

  • include 在請求中包含用戶憑據,並使用回應的用戶憑據。

PS. 可以將用戶憑據替換為 cookie 來理解。

錯誤原因

因為只要設了 crossorigin,瀏覽器設定 modeCORS ,也就會檢查請求標頭上的 Origin 是否吻合回傳的 Access-Control-Allow-Origin

例如,

// request headers
origin: https://www.hokang.info

// response headers
access-control-allow-origin: https://www.hokang.info
// or
access-control-allow-origin: *

則代表吻合通過。

而不設 crossorigin,瀏覽器的 modeNO-CORS,發出的請求也就不是 cross-origin HTTP request,當然也不會處理 CORS 相關的屬性。 而原本 script 標籤中 src 屬性就支援可取得跨域的資源。 所以,當加上 crossorigin=anonymous 而回應中卻沒有 access-control-allow-origin: * 時,反而不吻合 CORS 的規範。

這時可以

  • 拿掉 script 標籤中的 crossorigin=anonymous

  • 在伺服器的回應中加入標頭 access-control-allow-origin: *

那是不是在 script 標籤中的就都不要加入 crossorigin 屬性?

有無設定的差別在, 當 script 沒有通過 CORS`時,其發生錯誤只會傳最少資訊給 `window.onerror。 而當 CORS 並通過檢查後,則對跨域內容發生的錯誤就能列出更詳細的錯誤訊息。

閱讀在雲端