一文詳解CORS與預(yù)檢請(qǐng)求
CORS
出于安全性,瀏覽器限制腳本內(nèi)發(fā)起的跨源 HTTP 請(qǐng)求。例如,XMLHttpRequest
和 Fetch API
遵循。這意味著使用這些 API 的 Web 應(yīng)用程序只能從加載應(yīng)用程序的同一個(gè)域請(qǐng)求 HTTP 資源,除非響應(yīng)報(bào)文包含了正確 CORS 響應(yīng)頭。
跨源資源共享CORS,通過(guò)允許服務(wù)器標(biāo)示除了它自己以外的其他訪問(wèn)源、協(xié)議或端口,使得瀏覽器允許這些源訪問(wèn)加載自己的資源。簡(jiǎn)單講,就是目標(biāo)資源與當(dāng)前頁(yè)面不處于同一個(gè)域時(shí),瀏覽器的同源策略會(huì)阻止請(qǐng)求發(fā)出者獲得響應(yīng)數(shù)據(jù)。除非服務(wù)器允許跨域訪問(wèn),也就是支持CORS。
這是一些CORS相關(guān)的響應(yīng)頭信息,如果目標(biāo)資源服務(wù)器支持CORS,必須附帶一部分這些頭信息與瀏覽器交互
Access-Control-Allow-Origin:該字段必須出現(xiàn)在服務(wù)器的響應(yīng)中,表示允許跨域的源。如果是通配符( * ),表示接受任意域名的請(qǐng)求。 Access-Control-Allow-Methods:該字段表示接受的請(qǐng)求方法列表,多個(gè)值用逗號(hào)分隔。 Access-Control-Allow-Headers:該字段指定了實(shí)際請(qǐng)求可以攜帶的頭部信息,多個(gè)值用逗號(hào)分隔。 Access-Control-Allow-Credentials:該字段標(biāo)記是否允許發(fā)送 Cookie。如果為 true,則表示允許發(fā)送 Cookie。 Access-Control-Max-Age:該字段指定了預(yù)檢請(qǐng)求的有效期(單位為秒),即在指定時(shí)間內(nèi)不再發(fā)送預(yù)檢請(qǐng)求,直接發(fā)送實(shí)際請(qǐng)求即可。 Access-Control-Expose-Headers:該字段用于指定哪些頭部信息可以作為響應(yīng)的一部分被獲取到。
預(yù)檢請(qǐng)求
當(dāng)發(fā)送跨域請(qǐng)求時(shí),瀏覽器會(huì)先發(fā)送一個(gè)OPTIONS方法的預(yù)檢請(qǐng)求,探測(cè)服務(wù)器是否允許實(shí)際請(qǐng)求(POST、GET等)的跨域訪問(wèn)。服務(wù)器在接收到這個(gè)請(qǐng)求后,會(huì)返回一組響應(yīng)頭信息(詳見(jiàn)上文),包含了對(duì)CORS的支持情況和允許的請(qǐng)求方法,如果服務(wù)器對(duì)跨域請(qǐng)求進(jìn)行了允許,則瀏覽器才會(huì)真正地發(fā)送POST請(qǐng)求。如果服務(wù)器對(duì)預(yù)檢請(qǐng)求的響應(yīng)頭中拒絕跨域訪問(wèn)或者根本沒(méi)有任何CORS頭信息,瀏覽器會(huì)拋出錯(cuò)誤
因此,瀏覽器需要發(fā)送兩次請(qǐng)求來(lái)確認(rèn)服務(wù)器是否允許跨域請(qǐng)求,并確保安全性。
下面將演示觸發(fā)預(yù)檢請(qǐng)求的情況并且演示是處于跨域的環(huán)境下。
攜帶了自定義頭信息的請(qǐng)求
在這種情況下,無(wú)論任何請(qǐng)求方法都會(huì)觸發(fā)預(yù)檢請(qǐng)求
我們請(qǐng)求 https://api.github.com/
,這個(gè)接口支持跨域訪問(wèn),我們通過(guò)添加自定義請(qǐng)求頭,來(lái)觸發(fā)預(yù)檢請(qǐng)求
代碼:
var requestOptions = { method: 'GET', headers: { test: 'test' // 自定義的頭信息 }, redirect: 'follow' } fetch("https://api.github.com/", requestOptions) .then(response => response.json()) .then(result => console.log(result)) .catch(error => console.log('error', error))
運(yùn)行效果:
可以看到明明在代碼里面只有一次請(qǐng)求,可是瀏覽器卻發(fā)出了兩次請(qǐng)求,其中一個(gè)請(qǐng)求就是預(yù)檢請(qǐng)求
看下預(yù)檢請(qǐng)求和真實(shí)請(qǐng)求的請(qǐng)求頭:
不難發(fā)現(xiàn)
- 真實(shí)請(qǐng)求中,攜帶了自定義請(qǐng)求頭字段
- 在預(yù)檢請(qǐng)求頭中,
access-control-request-headers
字段標(biāo)識(shí)了真實(shí)請(qǐng)求頭中的自定義字段 - 在預(yù)檢請(qǐng)求頭中,
access-control-request-method
字段標(biāo)識(shí)了真實(shí)請(qǐng)求所使用的方法,這里是GET方法
總結(jié)來(lái)說(shuō),預(yù)檢請(qǐng)求會(huì)攜帶上真實(shí)請(qǐng)求使用的請(qǐng)求方法和自定義頭字段,去探測(cè)服務(wù)器是否允許這樣做。
再來(lái)看下預(yù)檢請(qǐng)求的響應(yīng)頭
這些用藍(lán)色方框圈起來(lái)的字段可以在上文中找到對(duì)應(yīng)的解釋。這里需要說(shuō)明一點(diǎn),可以從第一張圖看到真實(shí)請(qǐng)求是失敗的,原因在于我們添加的自定義請(qǐng)求頭字段test
并不在服務(wù)器允許的請(qǐng)求頭字段中,這一點(diǎn)從預(yù)檢請(qǐng)求的響應(yīng)頭字段access-control-allow-headers
很容易看出。
那么如果不攜帶test
頭信息,或者換成允許的頭字段,請(qǐng)求會(huì)成功,這一點(diǎn)留給讀者自行測(cè)試。
PUT,DELETE方法的請(qǐng)求
PUT請(qǐng)求
var raw = JSON.stringify({ "selected_organization_ids": [ 32, 91 ] }) var requestOptions = { method: 'PUT', body: raw, redirect: 'follow' } fetch("https://api.github.com/enterprises//actions/runner-groups//organizations", requestOptions) .then(response => response.text()) .then(result => console.log(result)) .catch(error => console.log('error', error))
DELETE請(qǐng)求
var requestOptions = { method: 'DELETE', redirect: 'follow' } fetch("https://api.github.com/admin/users//authorizations", requestOptions) .then(response => response.text()) .then(result => console.log(result)) .catch(error => console.log('error', error))
真實(shí)請(qǐng)求失敗是因?yàn)闆](méi)有傳遞正確的參數(shù)或者接口需要認(rèn)證。
服務(wù)器不允許跨域
上文的演示都是建立在目標(biāo)資源允許跨域訪問(wèn)的基礎(chǔ)上,下面演示目標(biāo)資源不允許跨域的情況
fetch("https://buy.vmall.com/getSkuRushbuyInfo.json", { method: 'get', headers: { test: 'test' } }).then(res => { return res.json() }).then(res => { console.log(res) })
觀察到預(yù)檢請(qǐng)求頭中沒(méi)有任何CORS響應(yīng)頭信息,表示服務(wù)器不允許跨域訪問(wèn),這時(shí)候?yàn)g覽器就會(huì)報(bào)錯(cuò)
在代碼層面也是可以捕捉到錯(cuò)誤的,但是演示代碼中沒(méi)有捕獲。
總結(jié)
- CORS是一套規(guī)范,指導(dǎo)瀏覽器和服務(wù)器之間如何進(jìn)行跨域資源共享
- 如果請(qǐng)求跨域,對(duì)于一些特定類(lèi)型的請(qǐng)求,瀏覽器會(huì)先發(fā)送一次預(yù)檢請(qǐng)求,去探測(cè)服務(wù)器是否允許
- 演示了一部分會(huì)觸發(fā)預(yù)檢請(qǐng)求的情況
以上就是一文詳解CORS與預(yù)檢請(qǐng)求的詳細(xì)內(nèi)容,更多關(guān)于CORS與預(yù)檢請(qǐng)求的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript和TypeScript中的void的具體使用
這篇文章主要介紹了JavaScript和TypeScript中的void的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09Element-UI的?InfiniteScroll?無(wú)限滾動(dòng)組件基本使用及應(yīng)用場(chǎng)景
這篇文章主要介紹了Element-UI的InfiniteScroll無(wú)限滾動(dòng)組件基本使用,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06js控制滾動(dòng)條緩慢滾動(dòng)到頂部實(shí)現(xiàn)代碼
滾動(dòng)條緩慢滾動(dòng)到頂部這樣的效果想必大家在瀏覽網(wǎng)頁(yè)的時(shí)候都有見(jiàn)過(guò)吧,本文使用js實(shí)現(xiàn)下,感興趣的你可不要錯(cuò)過(guò)了哈,希望可以幫助到你2013-03-03JS HTML5實(shí)現(xiàn)拖拽移動(dòng)列表效果
這篇文章主要為大家詳細(xì)介紹了JS HTML5實(shí)現(xiàn)拖拽移動(dòng)列表效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-07-07用nodejs訪問(wèn)ActiveX對(duì)象,以操作Access數(shù)據(jù)庫(kù)為例。
有人提問(wèn)“如果用nodejs訪問(wèn)sql server?” 找了找資料,發(fā)現(xiàn)有兩類(lèi)解決方法,使用第三方nodejs插件2011-12-12javascript 隨機(jī)數(shù) 與高級(jí)應(yīng)用 附vbscript(asp) 隨機(jī)數(shù)總結(jié)
有時(shí)忘了程序的隨機(jī)數(shù)函數(shù)或javascript和vbscript的隨機(jī)數(shù)混亂了,特總結(jié)下兩者的隨機(jī)數(shù)函數(shù),以備以后使用方便。2007-10-10JS+HTML實(shí)現(xiàn)的圓形可點(diǎn)擊區(qū)域示例【3種方法】
這篇文章主要介紹了JS+HTML實(shí)現(xiàn)的圓形可點(diǎn)擊區(qū)域,結(jié)合實(shí)例形式分析了javascript結(jié)合HTML元素屬性實(shí)現(xiàn)一個(gè)圓形的可點(diǎn)擊區(qū)域相關(guān)操作技巧,需要的朋友可以參考下2018-08-08