最簡單實現跨域的方法:用 Nginx 反向代理

良少發表於2016-07-26

什麼是跨域

跨域,指的是瀏覽器不能執行其他網站的指令碼。它是由瀏覽器的同源策略造成的,是瀏覽器對javascript施加的安全限制。

所謂同源是指,域名,協議,埠相同。瀏覽器執行javascript指令碼時,會檢查這個指令碼屬於那個頁面,如果不是同源頁面,就不會被執行。

同源策略的目的,是防止黑客做一些做奸犯科的勾當。比如說,如果一個銀行的一個應用允許使用者上傳網頁,如果沒有同源策略,黑客可以編寫一個登陸表單提交到自己的伺服器上,得到一個看上去相當高大上的頁面。黑客把這個頁面通過郵件等發給使用者,使用者誤認為這是某銀行的主網頁進行登陸,就會洩露自己的使用者資料。而因為瀏覽器的同源策略,黑客無法收到表單資料。

現在隨著RESTFUL的流行,很多應用提供http/https介面的API,通過xml/json格式對外提供服務,實現開放架構。如,微博、微信、天氣預報、openstack等網站和應用都提供restful介面。

Web應用也在向單頁面方向發展。越來越多的web應用現在是這樣的架構:

靜態單個web頁面

ajax呼叫

RESTFUL服務

我們本可以利用各個網站提供的API,做出很多精彩的Web應用。但瀏覽器執行javascript時的跨域限制,就成為了這類開放架構的攔路虎。

本文提出了一種簡單有效的方式解決跨域問題。

常用的跨域方法

常用的跨域方法有這樣一些:

1,使用iFrame訪問另一個域。 然後再從另一個頁面讀取iFrame的內容。jquery等有一些封裝。據說Firefox等可能不支援讀取另一個iFrame的內容。

2,jsonp。需要伺服器支援。使用script src動態得到一段java程式碼。是回撥頁面上的js函式,引數是一個json物件。jquery也有封裝。

3,設定http頭,Access-Control-Allow-Origin:*但據說IE有一些版本不識別這個http頭。

4,伺服器代理。如,伺服器寫一個url的處理action。其引數是一個url。這個伺服器會用引數拼湊一個url,用httpclient庫去執行url,然後把讀取的內容再輸出到http客戶端。

nginx反向代理實現跨域

上面提到的這些跨域方法,都有一些問題。有的不能支援所有瀏覽器,有的需要修改javascript程式碼,有的需要重寫伺服器端程式碼。有的在session等場景下會有問題。

其實,用nginx反向代理實現跨域,是最簡單的跨域方式。只需要修改nginx的配置即可解決跨域問題,支援所有瀏覽器,支援session,不需要修改任何程式碼,並且不會影響伺服器效能。

我們只需要配置nginx,在一個伺服器上配置多個字首來轉發http/https請求到多個真實的伺服器即可。這樣,這個伺服器上所有url都是相同的域名、協議和埠。因此,對於瀏覽器來說,這些url都是同源的,沒有跨域限制。而實際上,這些url實際上由物理伺服器提供服務。這些伺服器內的javascript可以跨域呼叫所有這些伺服器上的url。

下面,給出一個nginx支援跨域的例子,進行具體說明。

如,我們有兩個pythonflask開發的專案:testFlask1和testFlask2。

testFlask2專案上的javascript指令碼要通過ajax方式呼叫testFlask1的一個url,獲取一些資料。

正常情況下部署,就會有跨域問題,瀏覽器拒絕執行如下這樣的呼叫。

下面把testFlask2專案的javascrip檔案修改一下。這樣訪問同源的url,就不會有跨域問題。

但是,我們testFlask2專案實際上沒有partners/json這樣的url,那怎麼處理呢?

我們這樣編寫nginx的配置檔案:

我們把testFlask2專案部署在8080埠的根目錄下。把提供web服務的testFlask1專案部署在/partners目錄下。

但我們的testFlask1專案並不能處理/partners/json這樣的url請求。那怎麼辦呢?

通過 rewrite^.+partners/?(.*)$ /$1 break; 這一條命令,nginx可以把收到的/partners/*請求全部轉為/*請求後再轉發給背後的真實web伺服器。

這樣,RESTFUL的ajax客戶端程式,只需要給出特定字首的url就可以呼叫任意伺服器提供的RESTFUL介面了。

甚至,通過nginx的反向代理,我們還能呼叫其他公司開發的網站提供的RESTFUL介面。

如,

我們就把sohu網站整個搬到我們的8080:/sohu/目錄下了,我們的javascript就可以盡情呼叫其RESTFUL服務了。

順便說一下,rewrite^.+sohu/?(.*)$ /$1 break; 這句命令中,$1表示(.*)這個部分。第一對()內的引數是$1,第二對()內的引數就是$2,以此類推。

總結

本文介紹了利用nginx的反向代理的功能,實現跨域訪問任意應用和網站的方法。

nginx是一個高效能的web伺服器,常用作反向代理伺服器。nginx作為反向代理伺服器,就是把http請求轉發到另一個或者一些伺服器上。

通過把本地一個url字首對映到要跨域訪問的web伺服器上,就可以實現跨域訪問。

對於瀏覽器來說,訪問的就是同源伺服器上的一個url。而nginx通過檢測url字首,把http請求轉發到後面真實的物理伺服器。並通過rewrite命令把字首再去掉。這樣真實的伺服器就可以正確處理請求,並且並不知道這個請求是來自代理伺服器的。

簡單說,nginx伺服器欺騙了瀏覽器,讓它認為這是同源呼叫,從而解決了瀏覽器的跨域問題。又通過重寫url,欺騙了真實的伺服器,讓它以為這個http請求是直接來自與使用者瀏覽器的。

這樣,為了解決跨域問題,只需要動一下nginx配置檔案即可。簡單、強大、高效!

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

最簡單實現跨域的方法:用 Nginx 反向代理

相關文章