使用nginx代理解決跨域問(wèn)題

?? 先說(shuō)說(shuō)跨域這事情吧。早在13年,我剛接觸前端開(kāi)發(fā)的時(shí)候就遇到了跨域,那時(shí)候剛開(kāi)始流行前后端分離。解決跨域就是直接用get jsonp。還是小白的我,也沒(méi)有去想跨域的其它解決方式和為什么要采用這種解決方式。

?? 最近,做一個(gè)二次開(kāi)發(fā)的項(xiàng)目,也碰到了用網(wǎng)頁(yè)請(qǐng)求http post,瀏覽器跨域,不能獲取返回?cái)?shù)據(jù)的問(wèn)題,所以再次來(lái)梳理下這個(gè)跨域,為什么最后選擇了nginx代理。

? 首先,什么是跨域呢?首先需要了解的是同源和跨源的概念。對(duì)于相同源,其定義為:如果協(xié)議、端口(如果指定了一個(gè))和主機(jī)對(duì)于兩個(gè)頁(yè)面是相同的,則兩個(gè)頁(yè)面具有相同的源。只要三者之一任意一點(diǎn)有不同,那么就為不同源。同源策略限制從一個(gè)源加載的文檔或腳本如何與來(lái)自另一個(gè)源的資源進(jìn)行交互。這是一個(gè)用于隔離潛在惡意文件的關(guān)鍵的安全機(jī)制。當(dāng)一個(gè)資源從與該資源本身所在的服務(wù)器的域或端口不同的域或不同的端口請(qǐng)求一個(gè)資源時(shí),資源會(huì)發(fā)起一個(gè)跨域 HTTP 請(qǐng)求。跨域不一定是瀏覽器限制了發(fā)起跨站請(qǐng)求,而也可能是跨站請(qǐng)求可以正常發(fā)起,但是返回結(jié)果被瀏覽器攔截了。簡(jiǎn)單的來(lái)說(shuō),出于安全方面的考慮,頁(yè)面中的JavaScript無(wú)法訪問(wèn)其他服務(wù)器上的數(shù)據(jù),即“同源策略”。而跨域就是通過(guò)某些手段來(lái)繞過(guò)同源策略限制,實(shí)現(xiàn)不同服務(wù)器之間通信的效果。

? 跨域的解決方案也有很多種。

? 類型一:有些瀏覽器可以設(shè)置,降低它的安全性。但是對(duì)于一個(gè)網(wǎng)站,要求設(shè)置瀏覽器是不切合實(shí)際的。

? 類型二:直接用form方式,這種情況下不是ajax請(qǐng)求,而是直接訪問(wèn)目標(biāo)地址了,不存在跨域問(wèn)題,但是這個(gè)頁(yè)面已經(jīng)跳轉(zhuǎn)了。而我們想實(shí)現(xiàn)的只是取另外一個(gè)地址的數(shù)據(jù)到本地顯示而已。

? 類型三:服務(wù)端語(yǔ)言是能夠處理的情況下。

???? 1、CORS是一個(gè)W3C標(biāo)準(zhǔn),全稱是”跨域資源共享”(Cross-origin resource sharing)。它允許瀏覽器向跨源服務(wù)器,發(fā)出XMLHttpRequest請(qǐng)求,從而克服了AJAX只能同源使用的限制??缬蛸Y源共享( CORS )機(jī)制允許 Web 應(yīng)用服務(wù)器進(jìn)行跨域訪問(wèn)控制,從而使跨域數(shù)據(jù)傳輸?shù)靡园踩M(jìn)行。其需要服務(wù)端和客戶端同時(shí)支持。

?? 對(duì)于簡(jiǎn)單請(qǐng)求,瀏覽器直接發(fā)出CORS請(qǐng)求。具體來(lái)說(shuō),就是在頭信息之中,增加一個(gè)Origin字段。如果Origin指定的源,不在許可范圍內(nèi),服務(wù)器會(huì)返回一個(gè)正常的HTTP回應(yīng)。瀏覽器發(fā)現(xiàn),這個(gè)回應(yīng)的頭信息沒(méi)有包含Access-Control-Allow-Origin字段(詳見(jiàn)下文),就知道出錯(cuò)了,從而拋出一個(gè)錯(cuò)誤,被XMLHttpRequest的onerror回調(diào)函數(shù)捕獲。注意,這種錯(cuò)誤無(wú)法通過(guò)狀態(tài)碼識(shí)別,因?yàn)镠TTP回應(yīng)的狀態(tài)碼有可能是200。如果Origin指定的域名在許可范圍內(nèi),服務(wù)器返回的響應(yīng),會(huì)多出幾個(gè)頭信息字段。Access-Control-Allow-Origin該字段是必須的。它的值要么是請(qǐng)求時(shí)Origin字段的值,要么是一個(gè)*,表示接受任意域名的請(qǐng)求。Access-Control-Allow-Credentials該字段可選。Access-Control-Expose-Headers該字段可選。

?? 可以說(shuō)這種辦法主要在header上下功夫,設(shè)置Access-Control-Allow-Origin為所有*允許訪問(wèn)。雖然說(shuō)它支持所有的請(qǐng)求方式,post,delete,put等等,但是它不能兼容ie6,7等等。

?? 例如下圖的nodejs? express 例子:

?? 2、服務(wù)端的http ajax請(qǐng)求全部改為get jsonp方式。該方式能夠兼容老式瀏覽器。

?? 3、iframe window.name 這種傳值得方式很巧妙,兼容性也很好。但是在要訪問(wèn)數(shù)據(jù)的地址那個(gè)服務(wù)器要有一個(gè)空的中間頁(yè)面拿來(lái)用。

?? 4、postMessage,html5 window.postMessage。同iframe window.name有點(diǎn)像,也是需要服務(wù)端有個(gè)空的html拿來(lái)接收數(shù)據(jù)。而且現(xiàn)在的postMessage兼容性也不好。

? 5、document.domain修改為頂級(jí)域名。

? 6、WebSocket,協(xié)議不實(shí)行同源政策,只要服務(wù)器支持,就可以通過(guò)它進(jìn)行跨源通信。

類型四:不是簡(jiǎn)單的前后端。假如有個(gè)第三方的api,自己有一個(gè)網(wǎng)站前端,一個(gè)網(wǎng)站后端。

? 1、自己的網(wǎng)站端和后端源碼放在同一個(gè)服務(wù)端口和目錄下,不存在跨域。當(dāng)直接用網(wǎng)站前端的http訪問(wèn)第三方api,瀏覽器跨域。此時(shí),改為由網(wǎng)站后端的服務(wù)端語(yǔ)言訪問(wèn),做個(gè)中間人,將訪問(wèn)的數(shù)據(jù)給網(wǎng)頁(yè)前端。

? 2、網(wǎng)站前端和后端不是同源的,采用以上的跨域方案,譬如CORS。同樣的網(wǎng)站后端做中間人,訪問(wèn)第三方api,再轉(zhuǎn)給網(wǎng)頁(yè)前端。

? 3、使用nginx 反向代理解決跨域問(wèn)題。網(wǎng)站前端訪問(wèn)nginx服務(wù)的地址,nginx設(shè)置代理地址為訪問(wèn)第三方api地址,當(dāng)訪問(wèn)代理地址的時(shí)候,瀏覽器訪問(wèn)的是nginx服務(wù)的地址,實(shí)際是訪問(wèn)第三方api地址。



??? 注意:此時(shí),如果目錄下有個(gè)proxy.html,因?yàn)樵O(shè)置代理地址是/proxy,碰到這個(gè)地址就被轉(zhuǎn)到”https://192.168.18.175:8088/api/v1.0.2/“,所以要訪問(wèn)proxy.html是訪問(wèn)不到的。

?? 4、使用nginx代理地址是解決生產(chǎn)環(huán)境發(fā)布的問(wèn)題了,那么我在開(kāi)發(fā)的時(shí)候使用angular這樣需要打包的框架怎么辦呢。當(dāng)然在開(kāi)發(fā)環(huán)境下,angular也是由類似代理地址的解決方案的。

(1)創(chuàng)建配置代理文件:假設(shè)后端服務(wù)的訪問(wèn)地址為http://192.168.19.175:8088/api/v1.0.2/login,我們可以創(chuàng)建一個(gè)proxy.conf.json文件,放在package.json同目錄下。

(2)改寫package.json文件,采用--proxy-config命令(angular自帶的命令)。


(3)ajax訪問(wèn)代理地址

??? 此時(shí),執(zhí)行 npm start,即可發(fā)現(xiàn),瀏覽器訪問(wèn)http://localhost:4200/api/v1.0.2/login 的同源地址,實(shí)際上是訪問(wèn)http://192.168.18.175:8088/api/v1.0.2/login.

?? angular在開(kāi)發(fā)環(huán)境下代理地址的方法類似在生產(chǎn)環(huán)境下使用的nginx代理。但是測(cè)試angular是有一個(gè)/api代理地址的巧合。剛好第三方api上面的地址有個(gè)api,才能使用這個(gè)地址,并且能夠簡(jiǎn)寫一個(gè)api,才能成功訪問(wèn),如果更改為其它的,譬如proxy,就測(cè)試失敗。而且proxy.conf.json文件下的設(shè)置也只能是域名和端口。所以,本人測(cè)試,這或許是個(gè)巧合或者是缺陷。

五、其它

? 當(dāng)然,跨域這個(gè)算是歷史性的問(wèn)題,以后也會(huì)存在這個(gè)問(wèn)題。除了上面各種方法,以及根據(jù)各種方法使用的場(chǎng)合,還有許多其它的方法。例如各大流行框架react,vie應(yīng)該也有像angular一樣,能夠處理跨域的開(kāi)發(fā)環(huán)境方案,接下來(lái),還是要繼續(xù)學(xué)習(xí)和積累。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 題目1.什么是同源策略? 同源策略(Same origin Policy): 瀏覽器出于安全方面的考慮,只允許與本...
    FLYSASA閱讀 1,876評(píng)論 0 6
  • 1. 什么是跨域 跨域,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對(duì)JavaScri...
    cbw100閱讀 6,480評(píng)論 2 86
  • <轉(zhuǎn)>詳解跨域(最全的解決方案) 什么是跨域跨域,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的,...
    涅槃快樂(lè)是金閱讀 5,073評(píng)論 0 3
  • (1) 很崇拜那些能夠長(zhǎng)時(shí)間堅(jiān)持 做一件事情的人,不論事情是大是小,能夠長(zhǎng)時(shí)間如一日的堅(jiān)持,總能給人帶來(lái)振奮的力量...
    結(jié)硬寨打呆仗閱讀 382評(píng)論 0 0
  • 最羨古人之詩(shī),亦慕其生活之道。 不為名利,歸隱深林。 雖是粗繒大布身上裹,心卻逍遙自在似快活。 一弦一思一聲歌,泣...
    Mr小瘋子閱讀 250評(píng)論 0 0

友情鏈接更多精彩內(nèi)容