標籤:傳遞 access 目標 style 頁面 實現 覆蓋 訪問 shell
由於 Javascript 同源策略的存在使得一個源中載入來自其它源中資源的行為受到了限制。即會出現跨域請求禁止。
通俗一點說就是如果存在協議、網域名稱、連接埠或者子網域名稱不同服務端,或一者為IP地址,一者為網域名稱地址(在跨域問題上,域僅僅是通過“ url的首部 ”來識別而不會去嘗試判斷相同的IP地址對應著兩個域或者兩個域是否同屬同一個IP),之中任意服務端旗下的用戶端發起請求其它服務端資源的訪問行動都是跨域的,而瀏覽器為了安全問題一般都限制了跨域訪問,也就是不允許跨域請求資源。
但很多時候我們卻又不得不去跨域請求資源,這個時候就需要我們想方法去繞過瀏覽器同源策略的限制了。
常見的跨域請求解決方案:
1.Jsonp 利用script標籤發起get請求不會出現跨域禁止的特點實現
2.window.name+iframe 需要目標伺服器響應window.name
3.html5的 postMessage 主要側重於前端通訊,不同域下頁面之間的資料傳遞
4.Cors需要伺服器設定header:Access-Control-Allow-Origin
5.Nginx反向 Proxy 可以不需要目標伺服器配合,不過需要Nginx代理服務器,用於轉寄請求(服務端之間的資源請求不會有跨域限制)
下面分別說一下常用幾種解決方案的具體實現:
1 Jsonp
一般情況下由於同源策略我們不能夠通過XHR跨域去請求資源,但是我們的script標籤卻可以不受此限制成功的外鏈到來自於其他域下的資源。利用script標籤這個特點,我們可以成功的繞過同源策略。但這種方式存在局限性,我們只能夠發起get跨域請求。具體實現:
用戶端
服務端
script標籤跨域發起get請求,同時傳遞在用戶端已經註冊的全域函數 process_fun 作為查詢參數,服務端代碼提取查詢參數,並傳入需要返回的資料。script標籤還有一個特點,就是會立即執行調用所請求到的資源,所以這個時候服務端返回的 process_fun(data) 這一句代碼會被立即執行,即把資料 data 傳入我們事先定義好的函數 process_fun 中執行進一步的處理。
2 Cors
即跨域資源共用。實現cors通訊的關鍵是伺服器,只要伺服器實現了cors介面,就可以跨源通訊。不過不同於jsonp,cors對於IE8以下的瀏覽器是不支援的。
用戶端
服務端
跨域資源共用在我看來是最直接也最簡便的解決跨域問題的方式了,唯一的缺陷也就只是不能覆蓋支援所有的瀏覽器。用戶端不需要去做另外的改變,跟一般狀況下發送的非同步請求一致就行,甚至用戶端根本不需要知道所請求的介面是跨域的。而服務端所需要做的也只是返迴響應的同時設定 Access-Control-Allow-Origin
回應標頭部,意為“予許指定源(‘*’為任意源)發起跨域資源請求”。
3 window.name 和 postMessage
window.name 和 postMessage 主要都側重於純前端頁面之間的資料通訊,前者利用了 “ 在同一瀏覽器視窗載入的不同頁面( 無論它們是否不同域 ),共用同一個window.name,並且都對 window.name 有讀寫的許可權 ” 的這一特性來實現頁面間的資料交換,後者則是HTML5的API,不同域下的頁面在滿足一定關係的條件下可以通過此API跨域傳送資料。
4 Nginx反向 Proxy
Nginx反向 Proxy解決跨域問題則是利用了服務端之間的資源請求不會有跨域限制的特點實現的,具體來說就是我們前端發起的請求被Nginx攔截,再由Nginx代由轉寄請求到資原始伺服器請求資源。
比如現在我們有兩個Nodejs服務,分別是http://127.0.0.1:3000 和 http://127.0.0.1:5000,5000連接埠對應的服務端下的頁面需要發起請求3000連接埠所對應的服務端的資源,當然,在這種情況下如果不做任何的額外處理,請求會產生跨域。這個時候我們可以用Nginx來代理轉寄我們的請求,前端不去直接對資原始伺服器發起請求,而是改為直接存取Nginx伺服器,看到這裡你可能會問了,發起請求的前端頁面是屬於 http://127.0.0.1:5000 所在域下的,對Nginx服務發起請求難道不會和之前直接發起的請求一樣出現跨域嗎?所以這裡需要明白的一點是,一開始我們可能是通過 http://127.0.0.1:5000/ 這樣的路徑訪問到我們的頁面的,但是如果我們使用Nginx作為反向 Proxy,Proxy 伺服器監聽8080連接埠,我們這時候再訪問該頁面就不再是訪問 http://127.0.0.1:5000/ , 而是 http://127.0.0.1:8080/ 了,在Nginx中我們再做這樣的配置:
location / { proxy_pass http://127.0.0.1:5000;}
就能成功訪問到首頁了,而這個時候首頁是在 8080 連接埠所對應的域下(即Nginx服務)被渲染出來的,所以首頁這個時候便不再與 http://127.0.0.1:5000 同域, 而是與 Nginx 服務同域了,也就是說前端這時候對 Nginx 服務發起請求就不會再是跨域。
訪問 Nginx 我們可以實現了,接下來要做的就是對請求進行代理轉寄。
前端的 Ajax 請求是這樣的:
Nginx 需要對該請求進行攔截,所以可以做如下配置:
location配置的意思是對包含 “cross_origin” 請求攔截,並對請求路徑進行重寫,一開始請求路徑是 “/cross_origin/get_json?type=20170126” ,重寫後便成了 “/get_json?type=20170126”,$1代表(.*)中的內容,而(.*)則代表 cross_origin 後面的全部字元,也就是我們會把 cross_origin 部分去掉,但是保留 cross_origin 之後的所有字元,當然這一步並非是絕對必要的。接下來我們再把請求代理到 3000 連接埠所對應的資源服務,所以請求路徑從一開始的 “127.0.0.1:8080/cross_origin/get_json?type=20170126” 經過Proxy 伺服器Nginx之後變成了 “127.0.0.1:3000/get_json?type=20170126”。在 “127.0.0.1:3000” 下存在對應的介面:
現在在前端觸發點擊事件發起請求:
得到了響應,至此我們成功發起了跨域請求。
完。
Nginx反向 Proxy、CORS、JSONP等跨域請求解決方案總結