0. 环境信息
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. 问题描述
我们开发的客服系统,因为消息的到来,有的谷歌浏览器(V62)不支持http的消息提醒,要求https,故而,我们的系统,要将系统改造成https模式,另外,我们的系统,也有必要转化为https,为后续推广做准备。
2. 系统架构
LB+nginx+tomcat集群
3. 当前配置情况
SSL证书配置在LB上,nginx和tomcat服务器上,任然采用http协议通讯。即LB在接收到客户浏览器https请求消息后,将转发给LB下挂载的nginx上,都是以http的方式转发,nginx对这些请求进行反向代理,代理到后面的tomcat服务器上。
4. 遇到的问题
客服系统,有权限控制,基于tomcat的web应用,用户登录后,执行redirect跳转到指定的服务页面。就是这个跳转,遇到了问题,redirect在这里都被当做http跳转了。
登录前的样子:
登录后的样子:
问题主要发生在Tomcat7上,验证过tomcat8,是不存在问题的。
5. 如何解决
针对Tomcat7的这个问题,思路很简单,重点是解决redirect的时候,通知客户端浏览器以正确的scheme(https还是http)进行再次发起请求。
问题是, nginx这个时候收到的请求是来自LB的http请求了,怎么弄?其实是有办法的,可以利用HttpRequest中的referer字段,这个字段的含义,自行科普吧。将referer的请求scheme信息,用来作为当前请求的scheme,如此可以保证所有的请求都是同一个scheme,不会因为redirect而遗漏信息。
nginx里面相应的配置如下:
如上配置,经过nginx反向代理后的HttpServletRequest中header部分就带上了字段X-Forwarded-Proto。
另外一方面,就是tomcat里面,要做一个配置,让tomcat在解析请求和做重定向的时候,知道用什么协议。主要的配置在server.xml里面的Engine下,定义一个Value元素。
具体配置如下:
这个配置里面,重点是protocolHeader字段,意思就是说,当protocolHeader字段的值为protocolHeaderHttpsValue的https的时候,认为是安全连接,否则就是http的非安全连接。
对应的代码逻辑,可以看org.apache.catalina.valves.RemoteIpValve这个类的源码:
经过上面的分析和配置修改,最终很灵活的实现https和http同时工作。搞定这个问题,重点还是要对Http协议工作的流程有所了解,才能很容易的找到解决问题的思路。