一文詳解CORS與預(yù)檢請求
CORS
出于安全性,瀏覽器限制腳本內(nèi)發(fā)起的跨源 HTTP 請求。例如,XMLHttpRequest
和 Fetch API
遵循。這意味著使用這些 API 的 Web 應(yīng)用程序只能從加載應(yīng)用程序的同一個(gè)域請求 HTTP 資源,除非響應(yīng)報(bào)文包含了正確 CORS 響應(yīng)頭。
跨源資源共享CORS,通過允許服務(wù)器標(biāo)示除了它自己以外的其他訪問源、協(xié)議或端口,使得瀏覽器允許這些源訪問加載自己的資源。簡單講,就是目標(biāo)資源與當(dāng)前頁面不處于同一個(gè)域時(shí),瀏覽器的同源策略會阻止請求發(fā)出者獲得響應(yīng)數(shù)據(jù)。除非服務(wù)器允許跨域訪問,也就是支持CORS。
這是一些CORS相關(guān)的響應(yīng)頭信息,如果目標(biāo)資源服務(wù)器支持CORS,必須附帶一部分這些頭信息與瀏覽器交互
Access-Control-Allow-Origin:該字段必須出現(xiàn)在服務(wù)器的響應(yīng)中,表示允許跨域的源。如果是通配符( * ),表示接受任意域名的請求。 Access-Control-Allow-Methods:該字段表示接受的請求方法列表,多個(gè)值用逗號分隔。 Access-Control-Allow-Headers:該字段指定了實(shí)際請求可以攜帶的頭部信息,多個(gè)值用逗號分隔。 Access-Control-Allow-Credentials:該字段標(biāo)記是否允許發(fā)送 Cookie。如果為 true,則表示允許發(fā)送 Cookie。 Access-Control-Max-Age:該字段指定了預(yù)檢請求的有效期(單位為秒),即在指定時(shí)間內(nèi)不再發(fā)送預(yù)檢請求,直接發(fā)送實(shí)際請求即可。 Access-Control-Expose-Headers:該字段用于指定哪些頭部信息可以作為響應(yīng)的一部分被獲取到。
預(yù)檢請求
當(dāng)發(fā)送跨域請求時(shí),瀏覽器會先發(fā)送一個(gè)OPTIONS方法的預(yù)檢請求,探測服務(wù)器是否允許實(shí)際請求(POST、GET等)的跨域訪問。服務(wù)器在接收到這個(gè)請求后,會返回一組響應(yīng)頭信息(詳見上文),包含了對CORS的支持情況和允許的請求方法,如果服務(wù)器對跨域請求進(jìn)行了允許,則瀏覽器才會真正地發(fā)送POST請求。如果服務(wù)器對預(yù)檢請求的響應(yīng)頭中拒絕跨域訪問或者根本沒有任何CORS頭信息,瀏覽器會拋出錯誤
因此,瀏覽器需要發(fā)送兩次請求來確認(rèn)服務(wù)器是否允許跨域請求,并確保安全性。
下面將演示觸發(fā)預(yù)檢請求的情況并且演示是處于跨域的環(huán)境下。
攜帶了自定義頭信息的請求
在這種情況下,無論任何請求方法都會觸發(fā)預(yù)檢請求
我們請求 https://api.github.com/
,這個(gè)接口支持跨域訪問,我們通過添加自定義請求頭,來觸發(fā)預(yù)檢請求
代碼:
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)行效果:
可以看到明明在代碼里面只有一次請求,可是瀏覽器卻發(fā)出了兩次請求,其中一個(gè)請求就是預(yù)檢請求
看下預(yù)檢請求和真實(shí)請求的請求頭:
不難發(fā)現(xiàn)
- 真實(shí)請求中,攜帶了自定義請求頭字段
- 在預(yù)檢請求頭中,
access-control-request-headers
字段標(biāo)識了真實(shí)請求頭中的自定義字段 - 在預(yù)檢請求頭中,
access-control-request-method
字段標(biāo)識了真實(shí)請求所使用的方法,這里是GET方法
總結(jié)來說,預(yù)檢請求會攜帶上真實(shí)請求使用的請求方法和自定義頭字段,去探測服務(wù)器是否允許這樣做。
再來看下預(yù)檢請求的響應(yīng)頭
這些用藍(lán)色方框圈起來的字段可以在上文中找到對應(yīng)的解釋。這里需要說明一點(diǎn),可以從第一張圖看到真實(shí)請求是失敗的,原因在于我們添加的自定義請求頭字段test
并不在服務(wù)器允許的請求頭字段中,這一點(diǎn)從預(yù)檢請求的響應(yīng)頭字段access-control-allow-headers
很容易看出。
那么如果不攜帶test
頭信息,或者換成允許的頭字段,請求會成功,這一點(diǎn)留給讀者自行測試。
PUT,DELETE方法的請求
PUT請求
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請求
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í)請求失敗是因?yàn)闆]有傳遞正確的參數(shù)或者接口需要認(rèn)證。
服務(wù)器不允許跨域
上文的演示都是建立在目標(biāo)資源允許跨域訪問的基礎(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ù)檢請求頭中沒有任何CORS響應(yīng)頭信息,表示服務(wù)器不允許跨域訪問,這時(shí)候?yàn)g覽器就會報(bào)錯
在代碼層面也是可以捕捉到錯誤的,但是演示代碼中沒有捕獲。
總結(jié)
- CORS是一套規(guī)范,指導(dǎo)瀏覽器和服務(wù)器之間如何進(jìn)行跨域資源共享
- 如果請求跨域,對于一些特定類型的請求,瀏覽器會先發(fā)送一次預(yù)檢請求,去探測服務(wù)器是否允許
- 演示了一部分會觸發(fā)預(yù)檢請求的情況
以上就是一文詳解CORS與預(yù)檢請求的詳細(xì)內(nèi)容,更多關(guān)于CORS與預(yù)檢請求的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript和TypeScript中的void的具體使用
這篇文章主要介紹了JavaScript和TypeScript中的void的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09Element-UI的?InfiniteScroll?無限滾動組件基本使用及應(yīng)用場景
這篇文章主要介紹了Element-UI的InfiniteScroll無限滾動組件基本使用,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06用nodejs訪問ActiveX對象,以操作Access數(shù)據(jù)庫為例。
有人提問“如果用nodejs訪問sql server?” 找了找資料,發(fā)現(xiàn)有兩類解決方法,使用第三方nodejs插件2011-12-12javascript 隨機(jī)數(shù) 與高級應(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