一个使用struts2的网站在登录页面需要进行redirect跳转,大致如下:
<package name="admin" extends="httl-default" namespace="/admin">
<action name="login" class="com.zandili.tech.action.manage.LoginAdmin">
<result name="success" type="httl">/admin/login.httl</result>
<result name="error" type="redirect">/404</result>
<result name="loginok" type="redirect">/admin/index.do</result>
</action>
</package>
这是struts2中再简单不过的逻辑了,本地测试一切正常,但经过nginx代理后,这个奇葩问题就出现了。
我们假定两台tomcat的webapps目录下都有一个app目录是我们网站应用的目录,nginx配置如下:
upstream app_up {
server 192.168.0.5:8080;
server 192.168.0.6:8080;
}
server {
listen 80;
server_name www.zandili.com;
location / {
rewrite ^(.*)$ /app$1 break;
proxy_pass http://app_up;
proxy_redirect default;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
这样我们访问普通页面如http://www.zandili.com/index.do是没有问题的,nginx代理一切正常。
登录页面地址http://www.zandili.com/admin/login.do
提交表单后服务端判断用户登录成功后redirect到http://www.zandili.com/admin/index.do
这个时候我们用Firefox的firebug查看网络访问,就会发现,转向后的url地址为http://www.zandili.com/app/admin/index.do
目录中多了一个app目录,太意外了,app是后端tomcat下的目录,竟然在redirect的时候传递到了客户端,这不是我想要的。
此时更可怕的是如果程序里设置了404错误页,我们多了app目录的访问肯定找不到资源,就会无限重定向到404页面......
为这个问题苦恼啊,难道要为此放弃redirect不成?
曾经一度的解决方法是把网站部署到webapps下的ROOT目录,这样就不会多一个目录了(这是在逃避问题)。
仔细查看firebug提供的信息,发现这是个302重定向,多的这个app目录我只能理解为http://www.zandili.com/admin/login.do在进行redirect的时候,根据绝对路径获取到的是http://192.168.0.5:8080/app/admin/index.do的路径,nginx把这个跳转地址替换域名和端口后传递给客户端成http://www.zandili.com/app/admin/login.do这个地址重新发起请求,就出错了(这也就理解了redirect为什么是客户端转向)。
查了很多资料,一个字眼就频频出现,“proxy_redirect” ,这个在nginx里到底是什么作用?
NGINX的proxy_redirect功能比较强大,其作用是对发送给客户端的URL进行修改。
现在问题就出在发送给客户端的URL没有修改成我们需要的路径,看来这个有利于解决问题。
我们对nginx里的配置稍加修改
upstream app_up {
server 192.168.0.5:8080;
server 192.168.0.6:8080;
}
server {
listen 80;
server_name www.zandili.com;
location / {
rewrite ^(.*)$ /app$1 break;
proxy_pass http://app_up;
proxy_redirect default;#这个可以不要了,留着也没有啥危害
proxy_redirect http://www.zandili.com/app http://$host:$server_port;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
其中的
proxy_redirect http://www.zandili.com/app http://$host:$server_port;
就是把服务端的跳转指令中的url进行修改,我们把app目录给抹掉再返回给客户端,这样就正常了。
看来还是有必要进一步学习下nginx的知识。