為什么會(huì)發(fā)送OPTIONS請(qǐng)求

1

最近完成了一個(gè)番茄鬧鐘webApp:WJW-番茄土豆,小伙伴在幫忙測(cè)試bug的時(shí)候發(fā)現(xiàn)瀏覽器每次發(fā)送正式請(qǐng)求之前,都會(huì)發(fā)送一個(gè)OPTIONS請(qǐng)求:

微信圖片_20200525140732.png

于是小伙伴本著考察我的目的對(duì)我發(fā)出了提問:為什么會(huì)發(fā)送OPTIONS請(qǐng)求?

2

2.1 什么是OPTIONS請(qǐng)求?

CORS MDN是這么描述的

跨域資源共享標(biāo)準(zhǔn)新增了一組 HTTP 首部字段,允許服務(wù)器聲明哪些源站通過瀏覽器有權(quán)限訪問哪些資源。另外,規(guī)范要求,對(duì)那些可能對(duì)服務(wù)器數(shù)據(jù)產(chǎn)生副作用的 HTTP 請(qǐng)求方法(特別是 GET 以外的 HTTP 請(qǐng)求,或者搭配某些 MIME 類型的 POST 請(qǐng)求),瀏覽器必須首先使用OPTIONS方法發(fā)起一個(gè)預(yù)檢請(qǐng)求(preflight request),從而獲知服務(wù)端是否允許該跨域請(qǐng)求。服務(wù)器確認(rèn)允許之后,才發(fā)起實(shí)際的 HTTP 請(qǐng)求。在預(yù)檢請(qǐng)求的返回中,服務(wù)器端也可以通知客戶端,是否需要攜帶身份憑證(包括 Cookies 和 HTTP 認(rèn)證相關(guān)數(shù)據(jù))。

OPTIONS請(qǐng)求即預(yù)檢請(qǐng)求,可用于檢測(cè)服務(wù)器允許的http方法。當(dāng)發(fā)起跨域請(qǐng)求時(shí),由于安全原因,觸發(fā)一定條件時(shí)瀏覽器會(huì)在正式請(qǐng)求之前自動(dòng)先發(fā)起OPTIONS請(qǐng)求,即CORS預(yù)檢請(qǐng)求,服務(wù)器若接受該跨域請(qǐng)求,瀏覽器才繼續(xù)發(fā)起正式請(qǐng)求。

2.2 哪些請(qǐng)求會(huì)發(fā)送options請(qǐng)求?

這里就要說說請(qǐng)求的分類:簡(jiǎn)單請(qǐng)求和預(yù)檢請(qǐng)求。
簡(jiǎn)單請(qǐng)求:滿足以下幾種情況(日常開發(fā)基本上只會(huì)注意前兩種)

  1. 使用GET、POST、HEAD其中一種方法
  2. 只使用了如下的安全首部字段,不得人為設(shè)置其他首部字段
  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type 僅限以下三種:
    text/plain
    multipart/form-data
    application/x-www-form-urlencoded
  • HTML頭部header field字段:DPR、Download、Save-Data、Viewport-Width、WIdth
  1. 請(qǐng)求中的任意XMLHttpRequestUpload 對(duì)象均沒有注冊(cè)任何事件監(jiān)聽器;XMLHttpRequestUpload 對(duì)象可以使用 XMLHttpRequest.upload 屬性訪問
  2. 請(qǐng)求中沒有使用 ReadableStream 對(duì)象

預(yù)檢請(qǐng)求:滿足以下幾種情況

1.使用了PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH方法
2.人為設(shè)置了非規(guī)定內(nèi)的其他首部字段,參考上面簡(jiǎn)單請(qǐng)求的安全字段集合,還要特別注意Content-Type的類型

  1. XMLHttpRequestUpload 對(duì)象注冊(cè)了任何事件監(jiān)聽器
  2. 請(qǐng)求中使用了ReadableStream對(duì)象

請(qǐng)求附帶身份憑證 >. cookies

發(fā)起請(qǐng)求時(shí)設(shè)置withCredentials 標(biāo)志設(shè)置為true,從而向服務(wù)器發(fā)送cookie, 但是如果服務(wù)器端的響應(yīng)中未攜帶Access-Control-Allow-Credentials: true,瀏覽器將不會(huì)把響應(yīng)內(nèi)容返回給請(qǐng)求的發(fā)送者。
對(duì)于附帶身份憑證的請(qǐng)求,服務(wù)器不得設(shè)置Access-Control-Allow-Origin 的值為*, 必須是某個(gè)具體的域名。
注意,簡(jiǎn)單的GET請(qǐng)求不會(huì)觸發(fā)預(yù)檢,如果對(duì)此類帶有身份憑證請(qǐng)求的響應(yīng)中不包Access-Control-Allow-Credentials: true,這個(gè)響應(yīng)將被忽略掉,并且瀏覽器也不會(huì)將相應(yīng)內(nèi)容返回給網(wǎng)頁

2.3 OPTIONS請(qǐng)求有什么?

  1. 預(yù)檢請(qǐng)求頭request header的關(guān)鍵字段:
    Access-Control-Request-Method:告訴服務(wù)器實(shí)際請(qǐng)求所使用的 HTTP 方法
    Access-Control-Request-Headers:告訴服務(wù)器實(shí)際請(qǐng)求所攜帶的自定義首部字段

服務(wù)器基于從預(yù)檢請(qǐng)求頭部獲得的信息來判斷,是否接受接下來的實(shí)際請(qǐng)求。

  1. 預(yù)檢響應(yīng)頭response header的關(guān)鍵字段:
    Access-Control-Allow-Methods:返回了服務(wù)端允許的請(qǐng)求,包含GET/HEAD/PUT/PATCH/POST/DELETE
    Access-Control-Allow-Credentials:允許跨域攜帶cookie(跨域請(qǐng)求要攜帶cookie必須設(shè)置為true
    Access-Control-Allow-Origin:允許跨域請(qǐng)求的域名,這個(gè)可以在服務(wù)端配置一些信任的域名白名單
    Access-Control-Request-Headers:客戶端請(qǐng)求所攜帶的自定義首部字段content-type

此次options請(qǐng)求返回了響應(yīng)頭的內(nèi)容,但沒有返回響應(yīng)實(shí)體response body內(nèi)容。

2.4 OPTIONS請(qǐng)求是否可以優(yōu)化?

當(dāng)然是可以的:

  1. OPTIONS預(yù)檢請(qǐng)求的結(jié)果可以被緩存

·Access-Control-Max-Age這個(gè)響應(yīng)首部表示 preflight request (預(yù)檢請(qǐng)求)的返回結(jié)果(即 Access-Control-Allow-MethodsAccess-Control-Allow-Headers 提供的信息) 可以被緩存的最長(zhǎng)時(shí)間,單位是秒。(MDN)
·如果值為 -1,則表示禁用緩存,每一次請(qǐng)求都需要提供預(yù)檢請(qǐng)求,即用OPTIONS請(qǐng)求進(jìn)行檢測(cè)。

  1. 避免觸發(fā)
    參考2.2 哪些請(qǐng)求會(huì)發(fā)送options請(qǐng)求? ,通過設(shè)置請(qǐng)求(比如三種Content-Type)來避免觸發(fā)預(yù)檢請(qǐng)求。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容