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

于是小伙伴本著考察我的目的對(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ì)注意前兩種)
- 使用
GET、POST、HEAD其中一種方法- 只使用了如下的安全首部字段,不得人為設(shè)置其他首部字段
AcceptAccept-LanguageContent-LanguageContent-Type僅限以下三種:
text/plain
multipart/form-data
application/x-www-form-urlencodedHTML頭部header field字段:DPR、Download、Save-Data、Viewport-Width、WIdth
- 請(qǐng)求中的任意
XMLHttpRequestUpload對(duì)象均沒有注冊(cè)任何事件監(jiān)聽器;XMLHttpRequestUpload對(duì)象可以使用XMLHttpRequest.upload屬性訪問- 請(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的類型
XMLHttpRequestUpload對(duì)象注冊(cè)了任何事件監(jiān)聽器- 請(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)求有什么?
- 預(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)求。
- 預(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)然是可以的:
- OPTIONS預(yù)檢請(qǐng)求的結(jié)果可以被緩存
·
Access-Control-Max-Age這個(gè)響應(yīng)首部表示 preflight request (預(yù)檢請(qǐng)求)的返回結(jié)果(即Access-Control-Allow-Methods和Access-Control-Allow-Headers提供的信息) 可以被緩存的最長(zhǎng)時(shí)間,單位是秒。(MDN)
·如果值為 -1,則表示禁用緩存,每一次請(qǐng)求都需要提供預(yù)檢請(qǐng)求,即用OPTIONS請(qǐng)求進(jìn)行檢測(cè)。
- 避免觸發(fā)
參考2.2 哪些請(qǐng)求會(huì)發(fā)送options請(qǐng)求? ,通過設(shè)置請(qǐng)求(比如三種Content-Type)來避免觸發(fā)預(yù)檢請(qǐng)求。