CORS 為什麼要區分 簡單請求 和 預檢請求 ?

2021-09-28 10:48:26 字數 1653 閱讀 1812

cors(cross-origin resource sharing),跨源資源共享(一般俗稱『跨域請求』),想必大家都已經有基本的了解。如果你還不了解的話,可以閱讀mdn 上的介紹 ( ,這裡就不贅述了。

不過在學習cors時,有些朋友會有疑惑,為什麼cors要把請求分成兩類:簡單請求和預檢請求(preflighted requests)呢?

如果我們看簡單請求和預檢請求的區分,會看到有很多的條件:

看上去很是複雜。

那麼怎麼理解這些限制呢?

其實,簡單請求就是普通 html form 在不依賴指令碼的情況下可以發出的請求,比如表單的 method 如果指定為 post ,可以用 enctype 屬性指定用什麼方式對表單內容進行編碼,合法的值就是前述這三種。

非簡單請求就是普通 html form 無法實現的請求。比如 put 方法、需要其他的內容編碼方式、自定義頭之類的。

對於伺服器來說,第一,許多伺服器壓根沒打算給跨源用。當然你不給 cors 響應頭,瀏覽器也不會使用響應結果,但是請求本身可能已經造成了後果。所以最好是預設禁止跨源請求。

第二,要回答某個請求是否接受跨源,可能涉及額外的計算邏輯。這個邏輯可能很簡單,比如一律放行。也可能比較複雜,結果可能取決於哪個資源哪種操作來自哪個 origin。對瀏覽器來說,就是某個資源是否允許跨源這麼簡單;對伺服器來說,計算成本卻可大可小。所以我們希望最好不用每次請求都讓伺服器勞神計算。

cors-preflight 就是這樣一種機制,瀏覽器先單獨請求一次,詢問伺服器某個資源是否可以跨源,如果不允許的話就不發實際的請求。注意先許可再請求等於預設禁止了跨源請求。如果允許的話,瀏覽器會記住,然後發實際請求,且之後每次就都直接請求而不用再詢問伺服器否可以跨源了。於是,伺服器想支援跨源,就只要針對 preflight 進行跨源許可計算。本身真正的響應**則完全不管這個事情。並且因為 preflight 是許可式的,也就是說如果伺服器不打算接受跨源,什麼事情都不用做。

但是這機制只能限於非簡單請求。在處理簡單請求的時候,如果伺服器不打算接受跨源請求,不能依賴 cors-preflight 機制。因為不通過 cors,普通表單也能發起簡單請求,所以預設禁止跨源是做不到的。

既然如此,簡單請求發 preflight 就沒有意義了,就算發了伺服器也省不了後續每次的計算,反而在一開始多了一次 preflight。

有些人把簡單請求不需要 preflight 理解為『向下相容』。這也不能說錯。但嚴格來說,並不是『為了向下相容』而不能發。理論上瀏覽器可以區別對待表單請求和非表單請求 —— 對傳統的跨源表單提交不發 preflight,從而保持相容,只對非表單跨源請求發 preflight。

但這樣做並沒有什麼好處,反而把事情搞複雜了。比如本來你可以直接用指令碼發跨源普通請求,儘管(在伺服器預設沒有跨源處理的情況下)你無法得到響應結果,但是你的需求可能只是傳送無需返回,比如打個日誌。但現在如果伺服器不理解 preflight 你就幹不了這個事情了。

而且如果真的這樣做,伺服器就變成了預設允許跨源表單,如果想控制跨源,還是得(跟原本一樣)直接在響應處理中執行跨源計算邏輯;另一方面伺服器又需要增加對 preflight 請求的響應支援,執行類似的跨源計算邏輯以控制來自非表單的相同跨源請求。伺服器通常沒有區分表單/非表單差異的需求,這樣搞純粹是折騰伺服器端工程師。

所以簡單請求不發 preflight 不是因為不能相容,而是因為相容的前提下發 preflight 對絕大多數伺服器應用來說沒有意義,反而把問題搞複雜了。

CORS跨域簡單請求與非簡單請求

sr post get head nsr put delete sr one step 瀏覽器直接發出cors請求,並在頭部攜帶乙個origin欄位,伺服器根據這個值決定是否同意請求 origin 說明請求來自哪個源,包括協議 網域名稱 埠 host api.eurus.com nsr one st...

CORS跨域請求之簡單請求與非簡單請求

先來看乙個例子 定義 server01 的專案,在路由表中新增一條路由記錄 url r getdata.html views.get data 對應的檢視函式 定義 server02 專案,在路由表中新增一條路由記錄 url r index.html views.index 對應的檢視函式 from...

CORS跨域請求之簡單請求與非簡單請求

先來看乙個例子 定義server01的專案,在路由表中新增一條路由記錄 url r getdata.html views.get data 對應的檢視函式 定義server02專案,在路由表中新增一條路由記錄 url r index.html views.index 對應的檢視函式 from dja...