首先說一下,跨域它不是一個問題,它是瀏覽器的一種安全策略,叫同源策略。拿前后端分離項目來說,前端調(diào)試或者部署的地址,與api的地址,必須擁有相同的協(xié)議、域名、端口號。否則,前端請求后端的接口會報錯。
如何實現(xiàn)跨域呢?
很多文章都有介紹,使用jsonp、cors服務(wù)端配置、代理等等,jsonp這種黑科技還是盡量不用吧,有很大的局限性,并且前后端改動都比較麻煩。
從項目實踐的角度來講,前后端分離項目應(yīng)該這樣實現(xiàn)跨域:
開發(fā)階段,從我?guī)н^的項目發(fā)現(xiàn),很多時候前端會要求后端配置cors請求頭,然后后端無腦的設(shè)置Access-Control-Allow-Origin: *,上線的時候帶來很大的安全隱患。正確的姿勢應(yīng)該是前端來解決,前端小白可能驚呆了,咋解決啊?前端框架vue、react都提供了代理功能,配置proxy選項就好了,具體怎么配置前端自己去查查,框架的官方文檔都有介紹。
正式上線,這個時候通常使用代理,前端請求接口地址一律使用當前域名下的/api/xxx/xxx。然后配置web服務(wù)器,對/api/開頭的請求進行代理,轉(zhuǎn)發(fā)到后端服務(wù)器或者后端部署端口。
前后端分離項目跨域問題是不可避免的。通常情況下前端由React、Vue等框架編寫,通過ajax請求服務(wù)端API,傳輸數(shù)據(jù)用json格式。
那么為什么有跨域的問題呢?解決跨域問題有哪些方式?搞清楚這兩個問題我們需要了解一下什么是同源策略。
瀏覽器的同源策略
同源策略(Same origin policy)是一種安全約定,是所有主流瀏覽器最核心也是最基本的安全功能之一。同源策略規(guī)定:不同域的客戶端腳本在沒有明確授權(quán)的情況下,不能請求對方的資源。同源指的是:域名、協(xié)議、端口均相同。
比如我們訪問一個網(wǎng)站
http://www.test.com/index.html,
那么這個頁面請求如下地址得情況是這樣的:
另外,同源策略又分如下兩種情況:
-
DOM同源策略:禁止對不同源的頁面DOM進行操作,主要防止iframe的情況。比如iframe標簽里放一個支付寶付款的頁面,如果沒有同源策略,那么釣魚網(wǎng)站除了域名不同,其他的則可以和支付寶的網(wǎng)站一模一樣。
-
XMLHttpRequest同源策略:禁止使用XHR對象向不同源的服務(wù)器發(fā)起http請求。比如網(wǎng)站記錄了銀行的cookie,這個時候你訪問了惡意網(wǎng)站,黑客拿到你的cookie,再通過ajax請求之前的銀行網(wǎng)站,便可以輕易的拿到你的銀行信息。
所以,正是因為有了同源策略,大家的網(wǎng)絡(luò)環(huán)境才相對的安全一些。
跨域問題的解決辦法
了解了同源策略,就知道為什么會有跨域問題的產(chǎn)生了,都是為了安全。但是實際研發(fā)中,大家還是需要跨域去訪問資源。典型的應(yīng)用場景就是前后端分離的項目了。那么我們?nèi)绾稳ソ鉀Q跨域問題呢?
CORS-跨域資源共享
CORS是一種W3C標準,定義了當產(chǎn)生跨域問題的時候,客戶端與服務(wù)端如何通信解決跨域問題。實際上就是前后端約定好定義一些自定義的http請求頭,讓客戶端發(fā)起請求的時候能夠讓服務(wù)端識別出來該請求是過還是不過。
瀏覽器將CORS請求分為簡單請求和非簡單請求:
簡單請求
簡單請求必須滿足以下兩個條件:
-
請求方式必須是HEAD、GET、POST三種方法之一。
-
Http請求頭必須只能是:Accept、Accept-Lanuage、Content-Lanuage、Last-Event-ID、Content-Type,其中Content-Type只限于三個值 Application/x-www-form-urlencoded、multipart/form-data、text/plain。
非簡單請求
不滿足簡單請求條件的就是非簡單請求。針對非簡單請求,瀏覽器會發(fā)起預(yù)檢請求。預(yù)檢請求的意思是當瀏覽器檢查到你的頁面含有跨域請求的時候,會發(fā)送一個OPTIONS請求給對應(yīng)的服務(wù)器,以檢測服務(wù)器是否允許當前域名的跨域請求。如果服務(wù)端允許該域名請求,則返回204或200狀態(tài)碼,瀏覽器接收到允許請求時候再繼續(xù)發(fā)送對應(yīng)的GET/POST/PUT/DELETE請求。同時服務(wù)器端也會告知瀏覽器預(yù)檢請求的緩存時長是多少,在這個時間范圍內(nèi),瀏覽器不會再次發(fā)起預(yù)檢請求。
原理基本上就是上面說的這些,實際業(yè)務(wù)中我們?nèi)绾瓮ㄟ^配置來解決跨域問題呢?基本上常見的就是三種方式:
Nginx配置
通常我們在nginx增加如下配置即可解決跨域問題:

用nginx這種方式是最舒服的,不需要客戶端和服務(wù)端多做其他工作,對代碼無入侵。
jsonp
因為script標簽是不受瀏覽器同源策略的影響,允許跨域請求資源(我們的每一個頁面都引用了大量第三方j(luò)s文件)。所以可以利用動態(tài)創(chuàng)建script標簽,通過src屬性發(fā)起跨域請求,這就是jsonp的原理。但是jsonp只支持GET請求,所以并不是一種好的方式。
服務(wù)端代碼控制
可以在服務(wù)端增加對跨域請求的支持:

這種方式相當于全局過濾器,對所有請求都過濾一遍。
以上三種方式都可以一定程度上解決跨域問題,但是nginx配置和服務(wù)端控制不能同時存在,否則會報“Access-Control-Allow-Origin Not Allow Multiple value”的錯誤。個人比較推薦nginx配置的方式,一勞永逸,不需要每個web項目都去編寫跨域的代碼。
大家在工作中有沒有遇到過跨域問題呢?都是怎么解決的?歡迎評論區(qū)交流討論,共同學(xué)習(xí)~






