nginx反向代理 https內部定向到http報302問題解決方案,「親測」

0. 環境信息

nginx反向代理 https內部定向到http報302問題解決方案,「親測」

1. 問題描述

我們開發的客服系統,因為消息的到來,有的谷歌瀏覽器(V62)不支持http的消息提醒,要求https,故而,我們的系統,要將系統改造成https模式,另外,我們的系統,也有必要轉化為https,為後續推廣做準備。

2. 系統架構

LB+nginx+tomcat集群

nginx反向代理 https內部定向到http報302問題解決方案,「親測」

3. 當前配置情況

SSL證書配置在LB上,nginx和tomcat服務器上,任然採用http協議通訊。即LB在接收到客戶瀏覽器https請求消息後,將轉發給LB下掛載的nginx上,都是以http的方式轉發,nginx對這些請求進行反向代理,代理到後面的tomcat服務器上。

4. 遇到的問題

客服系統,有權限控制,基於tomcat的web應用,用戶登錄後,執行redirect跳轉到指定的服務頁面。就是這個跳轉,遇到了問題,redirect在這裡都被當做http跳轉了。

登錄前的樣子:

nginx反向代理 https內部定向到http報302問題解決方案,「親測」

登錄後的樣子:

nginx反向代理 https內部定向到http報302問題解決方案,「親測」

5. 如何解決

針對Tomcat7的這個問題,思路很簡單,重點是解決redirect的時候,通知客戶端瀏覽器以正確的scheme(https還是http)進行再次發起請求。

問題是, nginx這個時候收到的請求是來自LB的http請求了,怎麼弄?其實是有辦法的,可以利用HttpRequest中的referer字段,這個字段的含義,自行科普吧。將referer的請求scheme信息,用來作為當前請求的scheme,如此可以保證所有的請求都是同一個scheme,不會因為redirect而遺漏信息。

nginx裡面相應的配置如下:

location /CSS/websocket {

proxy_pass http://css_ws_svr;

proxy_set_header Host $host;

proxy_set_header Remote_Addr $remote_addr;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection "upgrade";

}

location /CSS {

proxy_pass http://css_svr;

proxy_set_header Host $host;

proxy_set_header Remote_Addr $remote_addr;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

set $mscheme $scheme;

if ($http_referer ~* ^https.*) {

set $mscheme "https";

}

proxy_set_header X-Forwarded-Proto $mscheme;

}

如上配置,經過nginx反向代理後的HttpServletRequest中header部分就帶上了字段X-Forwarded-Proto。

另外一方面,就是tomcat裡面,要做一個配置,讓tomcat在解析請求和做重定向的時候,知道用什麼協議。主要的配置在server.xml裡面的Engine下,定義一個Value元素。

具體配置如下:

<engine>

<realm>

<realm>

resourceName="UserDatabase"/>

/<realm>

<host>

unpackWARs="true" autoDeploy="true">

<valve>

prefix="localhost_access_log." suffix=".txt"

pattern="%h %l %u %t "%r" %s %b" />

<valve>

<context>

/<valve>

/<host>

這個配置裡面,重點是protocolHeader字段,意思就是說,當protocolHeader字段的值為protocolHeaderHttpsValue的https的時候,認為是安全連接,否則就是http的非安全連接。

對應的代碼邏輯,可以看org.apache.catalina.valves.RemoteIpValve這個類的源碼

public void invoke(org.apache.catalina.connector.Request request, Response response)

throws IOException, ServletException

{

......

if (protocolHeader != null) {

String protocolHeaderValue = request.getHeader(protocolHeader);

if (protocolHeaderValue != null)

{

if (protocolHeaderHttpsValue.equalsIgnoreCase(protocolHeaderValue)) {

request.setSecure(true);

request.getCoyoteRequest().scheme().setString("https");

setPorts(request, httpsServerPort);

} else {

request.setSecure(false);

request.getCoyoteRequest().scheme().setString("http");

setPorts(request, httpServerPort);

}

}

}

......

}

經過上面的分析和配置修改,最終很靈活的實現https和http同時工作。搞定這個問題,重點還是要對Http協議工作的流程有所瞭解,

Nginx,linux ,c++,服務器,ffmpeg,流媒體,嵌入式,等…………資料可私信後臺,〈資料〉兩字免費領取


分享到:


相關文章: