Nginx SSL+tomcat集群,request.getScheme() 取到https正确的协议详解 - Java高知 - CSDN博客

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

2017年04月15日 17:08:14 Java高知 阅读数:5910 标签: nginx tomcat ssl sheme https 更多

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


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


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

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

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


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



并且还发现

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

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


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

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

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


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

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

其中关键的语句为:

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高知群交流



comments powered by Disqus