nginx反向代理tomcat應用,struts2網站程式redirect時導致請求地址錯誤的解決方法

java、c#發表於2013-12-25

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

相關文章