Nginx SSL+tomcat集群,request.getScheme() 取到https正确的协议详解

原文地址:http://blog.csdn.net/tjcyjd/article/details/70185224


欢迎扫码加入Java高知群交流


    公司之前用的是http,但是出于苹果app审核和服务器安全性问题,要改为https,我们公司用的是沃通的ssl,按照沃通的官方文档提供的步骤完成服务器的配置。 架构上使用了 Nginx +tomcat 集群, 且nginx下配置了SSL,tomcat 没有配置SSL,项目使用https协议。


配置成功后明明是https url请求,发现 log里面,tomcat获取scheme的时候,一直是http,而不是想像中的https

[plain]  view plain  copy
  1. 0415 16:01:10 INFO  (PaymentInterceptor.java:44) preHandle() - requestStringForLog:    {  
  2.         "request.getRequestURL():": "http://m.xxx.com/payment/paymentChannel?id=212&s=a84485e0985afe97fffd7fd7741c93851d83a4f6",  
  3.         "request.getMethod:": "GET",  
  4.         "_parameterMap":         {  
  5.             "id": ["212"],  
  6.             "s": ["a84485e0985afe97fffd7fd7741c93851d83a4f6"]  
  7.         }  
  8.     }  

request.getRequestURL() 输出出来的 一直是 

http://m.xxx.com/payment/paymentChannel?id=212&s=a84485e0985afe97fffd7fd7741c93851d83a4f6 

但是浏览器中的URL却是 

https://m.xxx.com/payment/paymentChannel?id=212&s=a84485e0985afe97fffd7fd7741c93851d83a4f6


下面我们进一步研究发现,java API上写得很清楚:

getRequestURL():

[plain]  view plain  copy
  1. Reconstructs the URL the client used to make the request.   
  2.   
  3. The returned URL contains a protocol, server name, port number, and server path,   
  4. but it does not include query string parameters.  


也就是说, getRequestURL() 输出的是不带query string的路经(含协议,端口,server path等信息).



并且还发现

[java]  view plain  copy
  1. request.getScheme()  //总是 http,而不是实际的http或https  
  2. request.isSecure()  //总是false(因为总是http)  
  3. request.getRemoteAddr()  //总是 nginx 请求的 IP,而不是用户的IP  
  4. request.getRequestURL()  //总是 nginx 请求的URL 而不是用户实际请求的 URL  
  5. response.sendRedirect( 相对url )  //总是重定向到 http 上 (因为认为当前是 http 请求)  

那么解决方案有没有呢,答案是肯定的,其实解决方法非常的简单,只需要分别配置一下 Nginx 和 Tomcat 就好了,而不用从程序代码上修改。


1.配置nginx的转发项,配置文件为proxy.conf,内容如下:

[plain]  view plain  copy
  1. proxy_connect_timeout 300s;  
  2. proxy_send_timeout 900;  
  3. proxy_read_timeout 900;  
  4. proxy_buffer_size 32k;  
  5. proxy_buffers 4 64k;  
  6. proxy_busy_buffers_size 128k;  
  7. proxy_redirect off;  
  8. proxy_hide_header Vary;  
  9. proxy_set_header Accept-Encoding '';  
  10. proxy_set_header Referer $http_referer;  
  11. proxy_set_header Cookie $http_cookie;  
  12. proxy_set_header Host $host;  
  13. proxy_set_header X-Real-IP $remote_addr;  
  14. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  
  15.   
  16. proxy_set_header X-Forwarded-Proto  $scheme;  

其中的 proxy_set_header X-Forwarded-Proto $scheme; 起到了关键性的作用。


2.配置tomcat,配置文件为server.xml,内容如下:

[plain]  view plain  copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE server-xml [  
  3. <!ENTITY vhost-localhost SYSTEM "file:///usr/local/tomcat-interface/conf/vhost/localhost.xml">  
  4. ]>  
  5. <Server port="8006" shutdown="SHUTDOWN">  
  6.   <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>  
  7.   <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>  
  8.   <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>  
  9.   <Listener className="org.apache.catalina.core.AprLifecycleListener"/>  
  10.   
  11.   <GlobalNamingResources>  
  12.     <Resource name="UserDatabase" auth="Container"  
  13.               type="org.apache.catalina.UserDatabase"  
  14.               description="User database that can be updated and saved"  
  15.               factory="org.apache.catalina.users.MemoryUserDatabaseFactory"  
  16.               pathname="conf/tomcat-users.xml" />  
  17.   </GlobalNamingResources>  
  18.   
  19.   <Service name="Catalina">  
  20.     <Connector port="8080"  
  21.               protocol="org.apache.coyote.http11.Http11AprProtocol"  
  22.               connectionTimeout="20000"  
  23.               redirectPort="8443"  
  24.               maxThreads="1000"  
  25.               minSpareThreads="20"  
  26.               acceptCount="1000"  
  27.               debug="0"  
  28.               disableUploadTimeout="true"  
  29.           useBodyEncodingForURI="true"  
  30.               enableLookups="false"  
  31.               URIEncoding="UTF-8" />  
  32.     <Engine name="Catalina" defaultHost="localhost">  
  33.       <Valve className="org.apache.catalina.valves.RemoteIpValve"  
  34.         remoteIpHeader="X-Forwarded-For"  
  35.         protocolHeader="X-Forwarded-Proto"  
  36.         protocolHeaderHttpsValue="https"/>  
  37.       <Realm className="org.apache.catalina.realm.LockOutRealm">  
  38.         <Realm className="org.apache.catalina.realm.UserDatabaseRealm"  
  39.                resourceName="UserDatabase"/>  
  40.       </Realm>  
  41.       &vhost-localhost;  
  42.     </Engine>  
  43.   </Service>  
  44. </Server>  

其中关键的语句为:

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


配置双方的 X-Forwarded-Proto 就是为了正确地识别实际用户发出的协议是 http 还是 https。 

配置完成之后以下的请求访问

request.getScheme() 、request.isSecure() 、request.getRemoteAddr()、request.getRequestURL() 、response.sendRedirect( 相对url ) 

就都变为正确的结果了,就像用户在直接访问 Tomcat 一样。


欢迎扫码加入Java高知群交流

猜你喜欢

转载自blog.csdn.net/hh_hh1816/article/details/79611875