nginx反向代理https內(nèi)部定向到http報302的問題及解決
環(huán)境信息
Linux:Linux i-8emt1zr1 2.6.32-573.el6.x86_64 #1 SMP Wed Jul 1 18:23:37 EDT 2015 x86_64 x86_64 x86_64 GNU/Linux
nginx:nginx version: openresty/1.9.3.2
Tomcat:Server version: Apache Tomcat/7.0.64
1. 問題描述
我們開發(fā)的客服系統(tǒng),因為消息的到來,有的谷歌瀏覽器(V62)不支持http的消息提醒,要求https,故而,我們的系統(tǒng),要將系統(tǒng)改造成https模式,另外,我們的系統(tǒng),也有必要轉(zhuǎn)化為https,為后續(xù)推廣做準備。
2. 系統(tǒng)架構(gòu)
LB+nginx+tomcat集群

3. 當(dāng)前配置情況
SSL證書配置在LB上,nginx和tomcat服務(wù)器上,任然采用http協(xié)議通訊。
即LB在接收到客戶瀏覽器https請求消息后,將轉(zhuǎn)發(fā)給LB下掛載的nginx上,都是以http的方式轉(zhuǎn)發(fā),nginx對這些請求進行反向代理,代理到后面的tomcat服務(wù)器上。
4. 遇到的問題
客服系統(tǒng),有權(quán)限控制,基于tomcat的web應(yīng)用,用戶登錄后,執(zhí)行redirect跳轉(zhuǎn)到指定的服務(wù)頁面。
就是這個跳轉(zhuǎn),遇到了問題,redirect在這里都被當(dāng)做http跳轉(zhuǎn)了。
登錄前的樣子:

登錄后的樣子:

問題主要發(fā)生在Tomcat7上,驗證過tomcat8,是不存在問題的。
5. 如何解決
針對Tomcat7的這個問題,思路很簡單,重點是解決redirect的時候,通知客戶端瀏覽器以正確的scheme(https還是http)進行再次發(fā)起請求。
問題是, nginx這個時候收到的請求是來自LB的http請求了,怎么弄?其實是有辦法的,可以利用HttpRequest中的referer字段,這個字段的含義,自行科普吧。
將referer的請求scheme信息,用來作為當(dāng)前請求的scheme,如此可以保證所有的請求都是同一個scheme,不會因為redirect而遺漏信息。
nginx里面相應(yīng)的配置如下:
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;
}如上配置,經(jīng)過nginx反向代理后的HttpServletRequest中header部分就帶上了字段X-Forwarded-Proto。
另外一方面,就是tomcat里面,要做一個配置,讓tomcat在解析請求和做重定向的時候,知道用什么協(xié)議。
主要的配置在server.xml里面的Engine下,定義一個Value元素。
具體配置如下:
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<!-- This Realm uses the UserDatabase configured in the global JNDI
resources under the key "UserDatabase". Any edits
that are performed against this UserDatabase are immediately
available for use by the Realm. -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
<Valve className="org.apache.catalina.valves.RemoteIpValve" remoteIpHeader="X-Forwarded-For" protocolHeader="X-Forwarded-Proto" protocolHeaderHttpsValue="https"/>
<Context path="/CSS" docBase="/home/tomcat/app/cssv2"/>
</Host>
</Engine>這個配置里面,重點是protocolHeader字段,意思就是說,當(dāng)protocolHeader字段的值為protocolHeaderHttpsValue的https的時候,認為是安全連接,否則就是http的非安全連接。
對應(yīng)的代碼邏輯,可以看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);
}
}
}
......
}經(jīng)過上面的分析和配置修改,最終很靈活的實現(xiàn)https和http同時工作。
搞定這個問題,重點還是要對Http協(xié)議工作的流程有所了解,才能很容易的找到解決問題的思路。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
nginx學(xué)習(xí)總結(jié)五(nginx反向代理)
Nginx代理與負載均衡配置與優(yōu)化技巧,方便需要的朋友2012-11-11
詳解Nginx反向代理WebSocket響應(yīng)403的解決辦法
本篇文章主要介紹了詳解Nginx反向代理WebSocket響應(yīng)403的解決辦法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01
Windows Server 2016 MySQL數(shù)據(jù)庫安裝配置詳細安裝教程
這篇文章主要介紹了Windows Server 2016 MySQL數(shù)據(jù)庫安裝配置詳細安裝教程,需要的朋友可以參考下2017-08-08

