如何解決開發(fā)中常見的跨域問題
在我們?nèi)粘i_發(fā)中,跨域請(qǐng)求是不可避免的事情,本文主要是結(jié)合豬八戒的技術(shù)體系,介紹幾種常見的跨域問題的表現(xiàn),排查問題的思路。
一、跨域的概念
簡(jiǎn)單介紹一下跨域的基本概念,不滿足瀏覽器同源安全策略的請(qǐng)求即是跨域,同源安全策略因不同瀏覽器,以及不同版本有所不同,同源的含義通常為 協(xié)議(http\https),域名( www.taobao.com )和端口號(hào)( 80 , 8080 )都相同。
二、允許跨域的設(shè)置
允許跨域設(shè)置,主要是由服務(wù)器端處理,在豬八戒技術(shù)體系里即是在node層,分為兩種情況,簡(jiǎn)單請(qǐng)求和復(fù)雜請(qǐng)求。
1、簡(jiǎn)單請(qǐng)求
不會(huì)觸發(fā) CORS 預(yù)檢請(qǐng)求的請(qǐng)求一般稱為簡(jiǎn)單請(qǐng)求,且必須滿足以下所有條件:
條件1:使用下列方法之一:
GET
HEAD
- POST
條件2:Content-Type 的值僅限于下列三者之一:
text/plain
multipart/form-data
- application/x-www-form-urlencoded
條件3:不能手動(dòng)設(shè)置以下集合之外的請(qǐng)求頭:
accept
accept-language
- content-language
- content-type
條件4:請(qǐng)求中的任意 XMLHttpRequest 對(duì)象均沒有注冊(cè)任何事件監(jiān)聽器;XMLHttpRequest 對(duì)象可以使用 XMLHttpRequest.upload 屬性訪問。 (一般都滿足)
條件5:請(qǐng)求中沒有使用readableStream對(duì)象 (一般都滿足)
滿足簡(jiǎn)單請(qǐng)求的跨域只需要node層在接口響應(yīng)的時(shí)候設(shè)置以下頭部信息即可:
2、復(fù)雜請(qǐng)求
不符合以上條件的請(qǐng)求就肯定是復(fù)雜請(qǐng)求,且肯定會(huì)觸發(fā) CORS 預(yù)檢請(qǐng)求 ,比如常見的POST請(qǐng)求:Content-Type為application/json。
node層需做以下配置,以u(píng)topia舉例;
配置預(yù)檢請(qǐng)求:
接口請(qǐng)求設(shè)置:
特別注意:
"Access-Control-Allow-Origin"的值最合適的是配置白名單,因?yàn)閔eaders里的Origin某些客戶端在特定情況下請(qǐng)求的時(shí)候不會(huì)攜帶,如果設(shè)置為"*",根據(jù)w3c標(biāo)準(zhǔn)"Access-Control-Allow-Credentials"就不能設(shè)置為true,主流瀏覽器都會(huì)遵循此標(biāo)準(zhǔn),防止泄漏隱私數(shù)據(jù),在這種情況下會(huì)拒絕將數(shù)據(jù)返回給js, 如果不想配置白名單那么麻煩,常用的方式是通過請(qǐng)求參數(shù)將origin傳遞到utopia服務(wù)器。
三、常見的跨域表現(xiàn)和原因
1、因?yàn)槲丛O(shè)置允許跨域,不滿足瀏覽器同源安全策略
通??吹降目缬虻谋憩F(xiàn),就是下面這種報(bào)錯(cuò):
重點(diǎn)的報(bào)錯(cuò)信息是這個(gè), "No 'Access-Control-Allow-Origin' header is present on the requested resource" ,請(qǐng)求的資源上不存在訪問控制允許源標(biāo)頭,這種就直接排查接口的實(shí)現(xiàn)是否設(shè)置了允許跨域,如果確定允許跨域的設(shè)置沒有問題,繼續(xù)看下面的可能情況
注意: 排查允許跨域設(shè) 置的時(shí)候,要先明確當(dāng)前請(qǐng)求是簡(jiǎn)單請(qǐng)求還是復(fù)雜請(qǐng)求,兩種請(qǐng)求方式的跨域設(shè)置有差異。
2、"Access-Control-Allow-Origin"的值不正確
值不正確主要是兩種情況: 一種是“Ac cess-Con trol-Allow-Origin”的值 與當(dāng)前請(qǐng)求的站點(diǎn)不一樣 , 比如:
當(dāng)前請(qǐng)求的站點(diǎn)是 “http://local.test.zbjdev.com:3100”與接口設(shè)置的允許的跨域訪問的站點(diǎn)“https://chongqing.zbj.com”不 相等,自然就會(huì)訪問失敗,這種檢查一下配置就行了
另外一種就是“Access-Control-Allow-Origin”的值格式不正確,比如:
和第一種情況的報(bào)錯(cuò)非常相似,但原因其實(shí)截然不同,“Access-Control-Allow-Origin”的值應(yīng)該僅僅包含站點(diǎn)信息,不包含任何路徑信息,' http://local.test.zbjdev.com:8300/ '就是帶上路徑了,正確語(yǔ)法如下:
如果排除是"Access-Control-Allow-Origin"的值不正確導(dǎo)致的問題,請(qǐng)看下面的情況。
3、訪問接口被重定向了,但重定向的url不支持跨域訪問
這種情況常見因?yàn)榻涌谧隽说卿浵拗疲?qǐng)求的時(shí)候沒有帶上用戶登錄信息導(dǎo)致
報(bào)錯(cuò)信息里面會(huì)有關(guān)鍵的“redirected from”等重定向的信息,需要去排查是不是請(qǐng)求的時(shí)候是否存在有效的登錄cookie,或者是客戶端在請(qǐng)求的時(shí)候沒有帶上cookie信息,客戶端請(qǐng)求帶cookie配置以axios庫(kù)舉例:
特殊情況: 如果是復(fù)雜請(qǐng)求,瀏覽器會(huì)進(jìn)行一次 CORS 預(yù)檢請(qǐng)求 ,預(yù)檢請(qǐng)求是不會(huì)攜帶cookie的,確認(rèn)是這種情況,就不要對(duì)預(yù)檢請(qǐng)求做登錄限制。
4、接口只在代碼正常執(zhí)行的邏輯里設(shè)置了允許跨域,代碼執(zhí)行異常的響應(yīng)沒有設(shè)置允許跨域
這種情況非常隱蔽,在node層我們可以設(shè)置各種各樣的中間件來抽離一些公共邏輯,但是公共邏輯的異常報(bào)錯(cuò)響應(yīng),一般是不會(huì)有跨域相關(guān)的設(shè)置的,比如這段示范代碼:
在這段代碼的邏輯里面,會(huì)有一個(gè)“paramsCheck”的中間件對(duì)請(qǐng)求參數(shù)“text”是否為空做校驗(yàn),“text”不為空的情況下,在最后響應(yīng)客戶端的請(qǐng)求的時(shí)候會(huì)進(jìn)行允許跨域的設(shè)置,不會(huì)有問題,但如果“text”為空的時(shí)候,“paramsCheck”中間件會(huì)攔截,響應(yīng)客戶端,但是并沒有進(jìn)行允許跨域的設(shè)置,就會(huì)導(dǎo)致前端報(bào)錯(cuò),且報(bào)錯(cuò)信息即是普通跨域的樣子,并且因?yàn)闉g覽器同源安全策略,在chrome調(diào)試工具的network面板無法看到服務(wù)端任何響應(yīng)信息,具體表現(xiàn)可見下面的附圖:
我們?cè)倏戳硗庖欢问痉洞a,是常見的另一種沒有在異常邏輯進(jìn)行允許跨域設(shè)置,導(dǎo)致出現(xiàn)跨域報(bào)錯(cuò)的代碼:
四、總結(jié)
經(jīng)常遇到的跨域情況,我們可以按照以下這個(gè)思路去進(jìn)行排查:
希望以上內(nèi)容能對(duì)有需要的人有所幫助