LB+nginx+tomcat7集群模式下的https请求重定向(redirect)后变成http的解决方案
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里面相应的配置如下:
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 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字段,意思就是说,当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协议工作的流程有所了解,才能很容易的找到解决问题的思路。
若各位伙伴有更好的解决方案,也请分享或者一起探讨。
LB+nginx+tomcat7集群模式下的https请求重定向(redirect)后变成http的解决方案的更多相关文章
- Spark Streaming揭秘 Day31 集群模式下SparkStreaming日志分析(续)
Spark Streaming揭秘 Day31 集群模式下SparkStreaming日志分析(续) 今天延续昨天的内容,主要对为什么一个处理会分解成多个Job执行进行解析. 让我们跟踪下Job调用过 ...
- Spark Streaming揭秘 Day30 集群模式下SparkStreaming日志分析
Spark Streaming揭秘 Day30 集群模式下SparkStreaming日志分析 今天通过集群运行模式观察.研究和透彻的刨析SparkStreaming的日志和web监控台. Day28 ...
- 7.redis 集群模式的工作原理能说一下么?在集群模式下,redis 的 key 是如何寻址的?分布式寻址都有哪些算法?了解一致性 hash 算法吗?
作者:中华石杉 面试题 redis 集群模式的工作原理能说一下么?在集群模式下,redis 的 key 是如何寻址的?分布式寻址都有哪些算法?了解一致性 hash 算法吗? 面试官心理分析 在前几年, ...
- 就publish/subscribe功能看redis集群模式下的队列技术(一)
Redis 简介 Redis 是完全开源免费的,是一个高性能的key-value数据库. Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的持久化,可以将内存中 ...
- Redis集群模式下的redis-py-cluster方式读写测试
与MySQL主从复制,从节点可以分担部分读压力不一样,甚至可以增加slave或者slave的slave来分担读压力,Redis集群中的从节点,默认是不分担读请求的,从节点只作为主节点的备份,仅负责故障 ...
- 【Redis集群原理专题】分析一下相关的Redis集群模式下的脑裂问题!
技术格言 世界上并没有完美的程序,但是我们并不因此而沮丧,因为写程序就是一个不断追求完美的过程. 什么是脑裂 字面含义 首先,脑裂从字面上理解就是脑袋裂开了,就是思想分家了,就是有了两个山头,就是有了 ...
- Tomcat 集群模式下 Session 更新 Bug (redis memcached 及tomcat自已的集群)
从 excel 中导入数据入系统,我们用的是先上传文件至服务器再分析所上传的文件逐行导入. 就是执行了一循环,在当前循环位置标识一下客户端就知道执行的进度了,以前的方式 是用 session.setA ...
- Hadoop框架:集群模式下分布式环境搭建
本文源码:GitHub·点这里 || GitEE·点这里 一.基础环境配置 1.三台服务 准备三台Centos7服务,基础环境从伪分布式环境克隆过来. 133 hop01,134 hop02,136 ...
- 使用reids结合wcf实现集群模式下的聊天室功能
1.reids的特点 Redis数据库完全在内存中,使用磁盘仅用于持久性. 相比许多键值数据存储,Redis拥有一套较为丰富的数据类型(字符串,哈希,列表,集合,有序集合),. Redis可以将数据复 ...
随机推荐
- css 实现的网页布局
css 实现网页布局,上中下三部分,中间为固定宽度且分为左右两部分 <!DOCTYPE html> <html> <head> <meta charset ...
- 2017ICPC北京赛区网络赛 Minimum(数学+线段树)
描述 You are given a list of integers a0, a1, …, a2^k-1. You need to support two types of queries: 1. ...
- 第一篇 make与makefile介绍
我们在Linux系统中学习C语言或者C++语言时,大多数时候只是用gcc命令或者g++命令在命令行进行简单的编译.链接即可得到最终的可执行文件,进一步即可验证所写C/C++语言的正确性.但是,在大型工 ...
- WPA2 Key Reinstallation 漏洞
漏洞形成: 必要条件1:WPA2 协议存在一个消息重放漏洞,导致多组相同数据被使用了相同的密钥加密. ciphertext = plaintext xor AES(key, IV||counter) ...
- 服务器安装wordpress,搭建自己的博客平台
自己构造网站的话,建立一个简单的网页还可以(比如,yongjieshi.com),对于建立复杂的博客就需要借助第三方的工具,常见的有wordpress,在阿里云上安装wordpress,我主要参考了这 ...
- Gym.102006:Syrian Collegiate Programming Contest(寒假自训第11场)
学习了“叙利亚”这个单词:比较温和的一场:几何的板子eps太小了,坑了几发. A .Hello SCPC 2018! 题意:给定一个排列,问它是否满足,前面4个是有序的,而且前面4个比后面的都小. 思 ...
- BZOJ-5244 最大真因数(min25筛)
题意:一个数的真因数指不包括其本身的所有因数,给定L,R,求这个区间的所有数的最大真因数之和. 思路:min25筛可以求出所有最小因子为p的数的个数,有可以求出最小因子为p的所有数之和. 那么此题就是 ...
- react状态提升问题::::
父组件传值给子组件,只需要在组件上写上naverightstates={this.state.naverightstates},然后在子组件里面引用this.props.naverightstates ...
- 使用sync 修饰符------子组件内部可以修改props
首先看一个需求,外部点击一个按钮,让弹窗组件显示(也就是将弹窗组件显示的flag置为true),点击弹窗组件内部的某个按钮 ,让改props置为false,关闭弹窗,但是会报警告,因为内层组件不能修改 ...
- MySQL--批量插入导致自增跳号问题
对于批量插入数据的操作,MySQL申请自增的策略为: 在批量插入语句执行过程中,申请策略: .第一次申请自增值时,会分配1个 .在N次申请自增值时,会分配上一次(第N-1次)的2倍. 测试Demo: ...