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