問題的提出:最近單位遇到一個需求,單位a和單位b,都通過專線連接到我單位,單位b提出需要訪問單位a網絡中的一個網站應用,本來很簡單問題,只需要我單位中一台可以訪問兩邊網絡的服務器上,架設nginx就可以解決該問題,事實上,我天真了!
(ps:本文僅針對對nginx反向代理有一定了解的朋友,如不了解請自行百度)
問題出現在這個網站應用上,他們使用了cas架構,在系統登錄的url地址和應用的地址不在一起,如下:
當使用系統的地址訪問時,他跳轉到下面的位置,顯示了登錄頁面:
當登錄系統后,又跳轉回192.168.20.150這個地址上。
查了一下cas,應該是用於登錄權限管理的。
通過fiddle跟蹤,發現在使用http://192.168.20.164登錄時,返回了如下信息
紅線標出了,瀏覽器下次跳轉的url,繼續跳轉,返回:
繼續跳,返回:
到這里,再跳轉到index.aspx就進入系統了。
是不是有點暈!總結一下:
進入系統,一共進行了三次跳轉,系統的登錄首頁在192.168.20.164上面,點擊登錄成功后,就跳轉到192.168.20.150上面去。
可以看出192.168.20.164是一個管理登錄的服務器,系統的真實服務器在192.168.20.150上面。
好了,大體情況清楚了,但問題是如何實現我們的需求呢??
1、通過網絡方式,開通兩邊的網絡,這樣肯定應該是可以,但太暴力了,也不允許,不現實,pass掉。
2、在中間服務器,使用nginx反向代理,但常規的方式,顯然滿足不了當前的情況,如果瀏覽器根據響應返回的location跳轉,就會訪問不到了,只能看如何在響應頭返回前端瀏覽器前,更改掉Location,讓它繼續指向我們自己的nginx服務器地址。
所以,我安裝一個台新的centos服務器在192.168.253.155上面,安裝nginx 1.9.9,因為需要改變響應頭中的Location值,需額外安裝ngx_headers_more模塊。
在《nginx替換響應頭(重點:如何在替換時加上if判斷)》這篇文章中有詳細的介紹。
nginx.conf主要配置如下:
map $upstream_http_Location $location{
~http://192.168.20.150/(?<param>.*) $param;
default $upstream_http_Location;
}
... ...
server {
listen 80;
server_name localhost;
location /xt/ {
set $qz http://192.168.253.155/;
more_set_headers -s '302' 'Location:$qz$location';
add_header Cache-Control 'no-cache';
add_header Cache-Control 'no-store';
sub_filter '/smportal-cas/' '/xt/smportal-cas/';
sub_filter_once off;
proxy_pass http://192.168.20.164:XXXX/;
}
location / {
... ...
proxy_pass http://192.168.20.150/;
}
... ...
最上面的map用於將登錄頁面返回響應頭中Location為的內容映射到變量$location中去,我們可以看到,在192.168.20.164上登錄成功后,首先就跳轉到http://192.168.20.150/xxx/xxx.aspx?ticket=xxxxxx,如下圖:
這時我們通~http://192.168.20.150/(?<param>.*) $param;取出150/后面的內容(因為每次后面的內容會不同)賦到$location中。
(注:(?<xxx> xxxx)是nginx中通過正則取值到變量的方法,此處首先賦值給了$param,然后通過map映射到$location。
至於為什么不用$upstream_http_Location直接取值,用if判斷呢?前面推薦的那篇文章寫的很清楚。)
接下來配置,將http://192.168.253.155/xt/的訪問代理到http://192.168.20.164上面,讓用戶可以訪問登錄頁面。
其中
set $qz http://192.168.253.155/; #設置變量$qz為我們自己的地址
more_set_headers -s '302' 'Location:$qz$location'; #將$qz和$location(保存着剛才取到需跳轉url的后面路徑和參數部分)拼接成指向我們自己nginx的地址,即替換原先url中http://192.168.20.150為http://192.168.253.155
最后配置http://192.168.253.155/的訪問代理到http://192.168.20.150上面去,即完成了本次的任務。
(ps: sub_filter的部分,是因為在登錄頁面中有很js,包括登錄按鈕提交時的url都使用了絕對的地址,所以需要在返回頁面到前端前替換掉這些url,增加我們前輟/xt/,這樣訪問才沒有問題。
其實,實際情況中, 有很多的限制,比如單位b訪問我單位的nginx服務器時,由於中間有網絡設備不好調整,限制訪問端口只能用80,而不能增加其它端口,所以配置只能使用子路徑來區分多代理,本來可以用多端口就不用sub_filter替換內容了。
在實驗的過程中,也嘗試過用\代理登錄的192.168.20.164服務器,用子路徑\xt代理系統服務器,最后引出了cookie的設置問題,雖最終沒這樣設,但發現nginx可以設置cookie的path,以保證代理時路徑改變,cookie作對應的調整,特在此備注一下:
proxy_cookie_path / /xt/;#將cookie的path的/映射為 /xt/
感覺nginx真的很方便,原先為了實現反向代理、跨域,可是用編程實現的,唉。
)






