问题的提出:最近单位遇到一个需求,单位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真的很方便,原先为了实现反向代理、跨域,可是用编程实现的,唉。
)