CORS跨域

slowquery發表於2022-10-13

01、索引

waterflow.link/articles/1665656761...

1、為什麼跨域

跨域資源共享 (CORS) 是一種基於 HTTP 標頭的機制,它允許伺服器指示除其自身之外的任何來源(域、方案或埠),瀏覽器應允許從中載入資源。 CORS 還依賴於一種機制,瀏覽器透過該機制向託管跨域資源的伺服器發出“預檢”請求,以檢查伺服器是否允許實際請求。 在該預檢中,瀏覽器傳送指示 HTTP 方法的標頭和將在實際請求中使用的標頭。

跨域請求的示例:從 a.com 提供的前端 JavaScript 程式碼使用 ajax 向 b.com/data.json 發出請求。

出於安全原因,瀏覽器限制從指令碼發起的跨域 HTTP 請求。 例如,ajax 和 請求的 API 遵循同源策略。 這意味著使用這些 API 的 Web 應用程式只能從載入應用程式的同一來源請求資源,除非來自其他來源的響應包含正確的 CORS 標頭。

2、跨域的規則

CORS標準透過新增新的 HTTP 頭來工作,伺服器可以返回允許哪些來源從 Web 瀏覽器讀取該資訊。此外,對於可能對伺服器資料造成副作用的 HTTP 方法(特別是 GET 以外的 HTTP方法 ,或具有某些 MIME 型別的 POST),規範要求瀏覽器“預檢”請求(先傳送OPTIONS請求),然後在伺服器“允許”後傳送實際請求。

CORS 失敗會導致錯誤,但出於安全原因,JavaScript 無法獲得有關錯誤的詳細資訊。所有程式碼都知道發生了錯誤。確定具體出了什麼問題的唯一方法是檢視瀏覽器的控制檯以獲取詳細資訊。

3、跨域場景

1、不會觸發預檢

簡單的請求不會觸發預檢,那什麼是簡單的請求呢?

  • 首先請求方法必須是GET、HEAD、POST其中之一
  • 除了客戶端自動設定的header頭(比如:Connection、User-Agent等),只能設定如下的這些header頭
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type:只允許application/x-www-form-urlencoded、multipart/form-data、text/plain型別
    • Range:只能是一些簡單的header頭,比如bytes=256-或者bytes=127-255

下面是一個簡單請求的流程:

https://i.iter01.com/images/cf44614ae79fb11474ded488efe09f703180f1043326a4cf5b8fe0d1ba07ba74.png

  1. 首先客戶端會向a.com會向服務端b.com傳送請求,並帶上源域名。
  2. 作為響應,伺服器返回一個帶有 Access-Control-Allow-Origin: * 的 Access-Control-Allow-Origin 標頭,這意味著該資源可以被任何來源訪問。(一般允許某個域或者某幾個域,可以用正則)

2、會觸發預檢

和簡單請求不同,處於安全考慮,會先向“預檢”請求,瀏覽器首先使用 OPTIONS 方法向另一個源上的資源傳送 HTTP 請求,以確定實際請求是否可以安全傳送。

下面是預檢請求的流程:

https://i.iter01.com/images/2bbbdb57117cdfab5337e1037c1808b62c6ba4d40be7d9e6e16f8534b9a1ac04.png

  1. 首先客戶端header頭已經不符合簡單請求的header,這時會觸發預檢。
  2. 客戶端傳送OPTIONS請求,以獲取允許跨域的header頭,會返回204 No Content的狀態碼
  3. 預檢成功之後,客戶端會傳送正常的POST請求

3、nginx跨域配置

注意:如果nginx設定跨域重複,客戶端console也會提示重複跨域

add_header Access-Control-Allow-Origin * always; # 允許所有
add_header Access-Control-Allow-Methods 'PUT,POST,GET,DELETE,OPTIONS'; #允許指定的請求方法
add_header Access-Control-Allow-Headers 'token,eceibstoken,powercode,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; # 允許指定的header頭
add_header Access-Control-Expose-Headers *; # 指定客戶端可以訪問哪些header
# 如果是預檢請求,返回204
if ($request_method = OPTIONS) {
    return 204;
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章