Nginx SSL 結合Tomcat 重定向URL變成HTTP的問題

http://www.siven.net/posts/d925bb5d.htmlhtml

***********************************************nginx

問題描述

因爲要配置服務器(Nginx + Tomcat)的SSL的問題(Nginx同時監聽HTTPHTTPS),可是,若是用戶訪問的是HTTPS協議,而後Tomcat進行重定向的時候,卻變成了HTTP.apache

逐步實踐過程

在網上找了一些資料,有些是經過修改Nginx配置便可解決,也有隻對Tomcat配置進行調整解決的… 各說不一,如下對嘗試的解決過程進行記錄:tomcat

實踐一:Nginx新增配置

HTTP協議制轉爲https服務器

Nginx代理的配置,要添加如下內容:session

location / {
proxy_pass http://test-server;
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_set_header X-Forwarded-Proto $scheme;

# 做用是對發送給客戶端的URL進行修改, 將http協議強制轉爲https
proxy_redirect http:// https://;
}


爲了方便測試強制轉換, http(80)、https(443)共存proxy_redirect
server {
listen 80;
listen 443 ssl;
...
}


重定向測試

  • JAVA CODE:app

HttpServletResponse resp = (HttpServletResponse)response;
resp.sendRedirect("/static/html/index.html");

使用HTTP協議訪問nginx代理地址以後,URL被重定向爲HTTPS協議了, 以下圖所示:dom

固然直接使用HTTPS協議訪問, 確定也是沒有問題的,以下圖所示:post

轉發測試

  • JAVA CODE:測試

HttpServletResponse resp = (HttpServletResponse)response;
req.getRequestDispatcher("/static/html/index.html").forward(request, response);

測試結果與重定向一致, 無異常狀況;

測試總結

實際應用場景中,若是要求HTTPHTTPS協議共存的時候(請求的協議與響應的協議一致)就會出現HTTP請求被強轉爲HTTPS,嘗試將Nginx配置proxy_redirect http:// https://;註釋,最終使用HTTPS協議亦沒法正常跳轉;

實踐二:Tomcat新增配置

不修改Nginx的狀況下, 僅對Tomcat配置進行調整

server.xmlEngine模塊下面配置多一個如下的Valve

<Valve  className="org.apache.catalina.valves.RemoteIpValve" 
        remoteIpHeader="X-Forwarded-For" 
        protocolHeader="X-Forwarded-Proto" 
        protocolHeaderHttpsValue="https"/>

重定向測試

使用HTTPS協議訪問時,最終被重定向到HTTP

轉發測試

使用HTTPS協議訪問,轉發動做未出現問題

測試總結

重定向的時候, HTTPS協議被轉爲HTTP,測試結果不經過。

實踐三:終極方案

Nginx 配置

對過程一Nginx配置進行調整註釋或刪除proxy_redirect,最終以下:

location / {
proxy_pass http://test-server;
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_set_header X-Forwarded-Proto $scheme;
}



Tomcat 配置

參看:Tomcat配置

測試過程

HTTP協議請求

 

HTTPS協議請求

測試結果

測試經過,不管使用HTTP訪問仍是HTTPS訪問,最終返回都是根據請求的協議進行響應,問題解決。

完整配置

  • Nginx
worker_processes  1;

events {
worker_connections 1024;
}


http {
include mime.types;
default_type application/octet-stream;

sendfile on;

keepalive_timeout 65;

upstream test-server {
server 10.15.16.6:8280 weight=1;
}

server {
listen 80;
listen 443 ssl;
server_name localhost;

#ssl_certificate cert.pem;
#ssl_certificate_key cert.key;

ssl_certificate server.crt;
ssl_certificate_key server.key;

# ssl_session_cache shared:SSL:1m;
#ssl_session_timeout 5m;

# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;


location / {
proxy_pass http://test-server;
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_set_header X-Forwarded-Proto $scheme;
# proxy_redirect http:// https://;
}

}

}

//處理代碼段
        domainName = request.getRequestURL().toString();
        String X_Forwarded_Proto = httpRequest.getHeader("X-Forwarded-Proto");
        if(StringUtils.isNotBlank(X_Forwarded_Proto)){
            if(X_Forwarded_Proto.toLowerCase().contains("https") && !domainName.toLowerCase().startsWith("https://")){
                domainName = "https://" + domainName.substring(7);
            }
        }
相關文章
相關標籤/搜索