什麼時候會傳送options請求

熊也抱抱發表於2019-04-15

1 偶然的相遇——options請求

最近寫的專案,應用裡所有的ajax請求都傳送了2遍。由於新專案,基礎模組是新搭的,所以出現一些奇葩問題也是意料之中,啊終於第一次在chrome的devTools遇見了活的options請求。

什麼時候會傳送options請求

1.1 第1次請求

這裡首先傳送了一次額外的options請求,在瀏覽器裡看到請求request header 和 response header的資訊如下:

(1)預檢請求頭request header的關鍵欄位:

Request Header 作用
Access-Control-Request-Method 告訴伺服器實際請求所使用的 HTTP 方法
Access-Control-Request-Headers 告訴伺服器實際請求所攜帶的自定義首部欄位,本次實際請求首部欄位中content-type為自定義

伺服器基於從預檢請求頭部獲得的資訊來判斷,是否接受接下來的實際請求。

什麼時候會傳送options請求

(2)預檢響應頭response header的關鍵欄位:

response header 作用
Access-Control-Allow-Methods 返回了服務端允許的請求,包含GET/HEAD/PUT/PATCH/POST/DELETE
Access-Control-Allow-Credentials 允許跨域攜帶cookie(跨域請求要攜帶cookie必須設定為true)
Access-Control-Allow-Origin 允許跨域請求的域名,這個可以在服務端配置一些信任的域名白名單
Access-Control-Request-Headers 客戶端請求所攜帶的自定義首部欄位content-type

此次OPTIONS請求返回了響應頭的內容,但沒有返回響應實體response body內容。

什麼時候會傳送options請求

1.2 第2次請求

這是本來要傳送的請求,如圖所示是普通的post請求。其中Content-Typeapplication/json是此次和後端約定的請求內容格式,這個也是後面講到為什麼會傳送options請求的原因之一。

什麼時候會傳送options請求

2 關於OPTIONS請求

從很多資料我們可以瞭解到使用OPTIONS方法對伺服器發起請求,可以檢測伺服器支援哪些 HTTP 方法。但是這次我們並沒有主動去發起OPTIONS請求,那OPTIONS請求為何會自動發起?

2.1 OPTIONS請求自動發起

MDN的CORS一文中提到:

規範要求,對那些可能對伺服器資料產生副作用的 HTTP 請求方法(特別是 GET 以外的 HTTP 請求,或者搭配某些 MIME 型別的 POST 請求),瀏覽器必須首先使用 OPTIONS 方法發起一個預檢請求(preflight request),從而獲知服務端是否允許該跨域請求。

所以這個跨域請求觸發了瀏覽器自動發起OPTIONS請求,看看此次跨域請求具體觸發了哪些條件。

2.2 跨域請求時,OPTIONS請求觸發條件

CORS預檢請求觸發條件 本次請求是否觸發該條件
1. 使用了下面任一HTTP 方法:
PUT/DELETE/CONNECT/OPTIONS/TRACE/PATCH 否,本次為post請求
2. 人為設定了以下集合之外首部欄位:
Accept/Accept-Language/Content-Language/Content-Type/DPR/Downlink/Save-Data/Viewport-Width/Width 否,未設定其他頭部欄位
3. Content-Type 的值不屬於下列之一:
application/x-www-form-urlencoded、multipart/form-data、text/plain 是,為application/json

由於修改了Content-Type為application/json,觸發了CORS預檢請求。

3 優化OPTIONS請求:Access-Control-Max-Age 或者 避免觸發

可見一旦達到觸發條件,跨域請求便會一直髮送2次請求,這樣增加的請求數是否可優化呢?答案是可以,OPTIONS預檢請求的結果可以被快取。

Access-Control-Max-Age這個響應首部表示 preflight request (預檢請求)的返回結果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的資訊) 可以被快取的最長時間,單位是秒。(MDN)

如果值為 -1,則表示禁用快取,每一次請求都需要提供預檢請求,即用OPTIONS請求進行檢測。

評論區的朋友提醒了,儘量避免不要觸發OPTIONS請求,上面例子中把content-type改掉是可以的。在其他場景,比如跨域並且業務有自定義請求頭的話就很難避免了。現在使用的axios或者superagent等第三方ajax外掛,如果出現CORS預檢請求,可以看看預設配置或者二次封裝是否規範。

4 總結

OPTIONS請求即預檢請求,可用於檢測伺服器允許的http方法。當發起跨域請求時,由於安全原因,觸發一定條件時瀏覽器會在正式請求之前自動先發起OPTIONS請求,即CORS預檢請求,伺服器若接受該跨域請求,瀏覽器才繼續發起正式請求。

相關文章