reverse proxy(逆向代理)一般位于Web应用程序的前端,对用户屏蔽了后台的应用服务器。除了请求转发,动态负载平衡和缓存也是reverse proxy的主要功能。在配置逆向代理的时候,一个普遍存在的问题是URL转换。
比方说有一台应用服务器,它的访问地址是http://appserver:9080/app,该地址并不直接暴露和用户,而是由reverse proxy配置成一个对外可见的URL,如http://revproxy/home/app,它是用户最终在浏览器输入的地址。当reverse proxy收到这个请求后,把它转换成应用服务器地址后,将该请求(连同HTTP request header中的参数)转发给后台的应用服务器;应用服务器返回的内容再经reverse proxy,最后回到用户浏览器。
一个常见的问题是如果应用服务器返回的HTML页面包含了在该应用服务器上有效的绝对或者相对路径时,reverse proxy该如何处理?如果是绝对路径的话,那么用户在点击页面上这个链接的时候就会跳过reverse proxy直接连到应用服务器上;如果是相对路径,如”/app” 的话,那么如果reverse proxy自己的URL前面又填加了新的目录名,如上面提到的“/home”,那么这个URL到用户那里就会成为”http://revproxy/app”,同样也是错误的。
reverse proxy的一个重要功能是地址转换,在WebSphere Edge Components(早先的 Edge Server)里可以通过配置一些地址转换规则来解决这个问题。它的工作原理大致是这样:在reverse proxy收到从应用服务器返回的HTML内容后,对其进行内容扫描,如果发现如”href”, “src” 等之类包含URL链接的标签时,根据预先设定的规则把它们替换成对外可用的地址。这样原来页面中的绝对、相对地址经转换后成为最终用户可以访问的地址。需要注意的是,reverse proxy对HTML的扫描是有一定限制的,如果这个绝对或者相对的URL是嵌入的JavaScript里,通过在浏览器端解释动态生成,或者存在于其他一些非链接性质的标签中,reverse proxy是没有办法对这些URL进行转换的。这样漏网的URL将直接暴露给用户。
解决页面中无法被翻译的绝对地址,似乎必须要修改应用程序;而对于无法被翻译的相对地址,可以在reverse proxy通过URL映射来解决。URL映射的原理是当reverse proxy接收到来自用户的HTTP 请求后,如果该URL满足预先定义的模式,则进行替换。比如在WebSphere Edge Components 中可以设定如下的地址转换规则:
Map /app/* /home/app/*。
如此一来,URL地址的转换问题基本得到解决。现在,还剩下两个问题需要考虑:
1. 当后台的应用服务器通过HTTP 301/302进行地址重定向的时候,reverse proxy必须也对该地址进行翻译。在edge中,可以使用下面的命令实现:
ReversePass http://appserver:9080/app/* http://revproxy/home/app/*
2. Cookie的作用域
当用户在应用服务器上登录后,往往会得到一个或多个cookie。在J2EE环境下,服务器端的session变量会产生一个名为”JSESSIONID“的cookie变量送给浏览器,同时指定该变量的作用域,如”path=/”或者”path=/app”。如果是前者那样的根目录,则没有问题,但如果是后者的话,如果reverse proxy原封不动的将该cookie值转发给用户浏览器的话,那么当用户再次发出如”/home/app”,这样的URL请求时,此cookie是不会放在HTTP请求头部中的,因为这个请求的作用域是“/home”,而不是”/app”。cookie作用域失效往往表现为用户的”伪登录“,即在后台服务器上已经登录但通过reverse proxy的话还是出现无法正常登录的情况。
在edge components里,可以使用下面的配置方案解决cookie作用域修改问题:
JunctionRewriteSetCookiePath /app/* /home/app/*
不过由于WebSphere Edge Components 6.1里的一个bug,该功能存在故障,需要获取指定的补丁更新方可使用。
另外,在应用服务器这端,如果可以指定cookie的path永远为根目录,会减少很多麻烦(在Lotus Connections 1.0/1.0.1里,cookie的path为根目录”path=/”以实现多个功能模块的单点登录SSO)。我在Tomcat下测试时发现,Tomcat生成JSESSIONID时,缺省的path就是当前webapp的context root,而不是根目录。如要强行指定Tomcat生成的cookie的path,需要在其”server.xml”配置文件中的”Connector“段中加入‘ emptySessionPath=”true” ’。
有关reverse proxy,如edge components中还有很多复杂的问题这里尚未涉及,如SSL连接、证书等网络安全相关配置。希望此文可以给reverse proxy,尤其是IBM WebSphere Edge Components的用户一点帮助。
PS:有关edge 6.1的配置,目前最完整的官方文档在此。