一個使用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的知識。