如何解決開發(fā)中常見的跨域問題
在我們?nèi)粘i_發(fā)中,跨域請求是不可避免的事情,本文主要是結(jié)合豬八戒的技術(shù)體系,介紹幾種常見的跨域問題的表現(xiàn),排查問題的思路。
一、跨域的概念
簡單介紹一下跨域的基本概念,不滿足瀏覽器同源安全策略的請求即是跨域,同源安全策略因不同瀏覽器,以及不同版本有所不同,同源的含義通常為 協(xié)議(http\https),域名( www.taobao.com )和端口號( 80 , 8080 )都相同。
二、允許跨域的設(shè)置
允許跨域設(shè)置,主要是由服務(wù)器端處理,在豬八戒技術(shù)體系里即是在node層,分為兩種情況,簡單請求和復(fù)雜請求。
1、簡單請求
不會觸發(fā) CORS 預(yù)檢請求的請求一般稱為簡單請求,且必須滿足以下所有條件:
條件1:使用下列方法之一:
GET
HEAD
- POST
 
條件2:Content-Type 的值僅限于下列三者之一:
text/plain
multipart/form-data
- application/x-www-form-urlencoded
 
條件3:不能手動設(shè)置以下集合之外的請求頭:
accept
accept-language
- content-language
 - content-type
 
條件4:請求中的任意 XMLHttpRequest 對象均沒有注冊任何事件監(jiān)聽器;XMLHttpRequest 對象可以使用 XMLHttpRequest.upload 屬性訪問。 (一般都滿足)
條件5:請求中沒有使用readableStream對象 (一般都滿足)
滿足簡單請求的跨域只需要node層在接口響應(yīng)的時候設(shè)置以下頭部信息即可:

2、復(fù)雜請求
不符合以上條件的請求就肯定是復(fù)雜請求,且肯定會觸發(fā) CORS 預(yù)檢請求 ,比如常見的POST請求:Content-Type為application/json。
node層需做以下配置,以utopia舉例;
配置預(yù)檢請求:

接口請求設(shè)置:

特別注意:
"Access-Control-Allow-Origin"的值最合適的是配置白名單,因為headers里的Origin某些客戶端在特定情況下請求的時候不會攜帶,如果設(shè)置為"*",根據(jù)w3c標(biāo)準(zhǔn)"Access-Control-Allow-Credentials"就不能設(shè)置為true,主流瀏覽器都會遵循此標(biāo)準(zhǔn),防止泄漏隱私數(shù)據(jù),在這種情況下會拒絕將數(shù)據(jù)返回給js, 如果不想配置白名單那么麻煩,常用的方式是通過請求參數(shù)將origin傳遞到utopia服務(wù)器。
三、常見的跨域表現(xiàn)和原因
1、因為未設(shè)置允許跨域,不滿足瀏覽器同源安全策略
通常看到的跨域的表現(xiàn),就是下面這種報錯:
重點的報錯信息是這個, "No 'Access-Control-Allow-Origin' header is present on the requested resource" ,請求的資源上不存在訪問控制允許源標(biāo)頭,這種就直接排查接口的實現(xiàn)是否設(shè)置了允許跨域,如果確定允許跨域的設(shè)置沒有問題,繼續(xù)看下面的可能情況
注意: 排查允許跨域設(shè) 置的時候,要先明確當(dāng)前請求是簡單請求還是復(fù)雜請求,兩種請求方式的跨域設(shè)置有差異。
2、"Access-Control-Allow-Origin"的值不正確
值不正確主要是兩種情況: 一種是“Ac cess-Con trol-Allow-Origin”的值 與當(dāng)前請求的站點不一樣 , 比如:
當(dāng)前請求的站點是 “http://local.test.zbjdev.com:3100”與接口設(shè)置的允許的跨域訪問的站點“https://chongqing.zbj.com”不 相等,自然就會訪問失敗,這種檢查一下配置就行了
另外一種就是“Access-Control-Allow-Origin”的值格式不正確,比如:
和第一種情況的報錯非常相似,但原因其實截然不同,“Access-Control-Allow-Origin”的值應(yīng)該僅僅包含站點信息,不包含任何路徑信息,' http://local.test.zbjdev.com:8300/ '就是帶上路徑了,正確語法如下:

如果排除是"Access-Control-Allow-Origin"的值不正確導(dǎo)致的問題,請看下面的情況。
3、訪問接口被重定向了,但重定向的url不支持跨域訪問
這種情況常見因為接口做了登錄限制,但請求的時候沒有帶上用戶登錄信息導(dǎo)致

報錯信息里面會有關(guān)鍵的“redirected from”等重定向的信息,需要去排查是不是請求的時候是否存在有效的登錄cookie,或者是客戶端在請求的時候沒有帶上cookie信息,客戶端請求帶cookie配置以axios庫舉例:

特殊情況: 如果是復(fù)雜請求,瀏覽器會進(jìn)行一次 CORS 預(yù)檢請求 ,預(yù)檢請求是不會攜帶cookie的,確認(rèn)是這種情況,就不要對預(yù)檢請求做登錄限制。
4、接口只在代碼正常執(zhí)行的邏輯里設(shè)置了允許跨域,代碼執(zhí)行異常的響應(yīng)沒有設(shè)置允許跨域
這種情況非常隱蔽,在node層我們可以設(shè)置各種各樣的中間件來抽離一些公共邏輯,但是公共邏輯的異常報錯響應(yīng),一般是不會有跨域相關(guān)的設(shè)置的,比如這段示范代碼:


在這段代碼的邏輯里面,會有一個“paramsCheck”的中間件對請求參數(shù)“text”是否為空做校驗,“text”不為空的情況下,在最后響應(yīng)客戶端的請求的時候會進(jìn)行允許跨域的設(shè)置,不會有問題,但如果“text”為空的時候,“paramsCheck”中間件會攔截,響應(yīng)客戶端,但是并沒有進(jìn)行允許跨域的設(shè)置,就會導(dǎo)致前端報錯,且報錯信息即是普通跨域的樣子,并且因為瀏覽器同源安全策略,在chrome調(diào)試工具的network面板無法看到服務(wù)端任何響應(yīng)信息,具體表現(xiàn)可見下面的附圖:

我們再看另外一段示范代碼,是常見的另一種沒有在異常邏輯進(jìn)行允許跨域設(shè)置,導(dǎo)致出現(xiàn)跨域報錯的代碼:

四、總結(jié)
經(jīng)常遇到的跨域情況,我們可以按照以下這個思路去進(jìn)行排查:

希望以上內(nèi)容能對有需要的人有所幫助















 
 
 












 
 
 
 