背景:1、架构是用的是tomcat+nginx,框架是单体的springboot系列;nginx配置了证书,采用https访问
问题:发现用https访问首页之后,验证码加载不出来
解决:经排查发现验证码后台的链接变成了http,提示跨域访问,经百度查询,使用一下方案解决:Nginx SSL 结合Tomcat 重定向URL变成HTTP的问题 - 程序员大本营 (pianshen.com)
我采用的是第一种新增nginx配置,不需要改其它的,这个方案要求访问必须只能https访问,如果访问要求兼容https以及http的可以看一下最终解决方案(未检验)
防止网址内容找不到,把内容复制到下面:
问题描述
由于要配置服务器(Nginx + Tomcat)的SSL的问题(Nginx同时监听HTTP
和HTTPS
),但是,如果用户访问的是HTTPS
协议,然后Tomcat进行重定向的时候,却变成了HTTP
.
逐步实践过程
在网上找了一些资料,有些是通过修改Nginx配置即可解决,也有只对Tomcat配置进行调整解决的… 各说不一,以下对尝试的解决过程进行记录:
实践一:Nginx新增配置
HTTP协议制转为https
Nginx代理的配置,要添加以下内容:
location / { proxy_pass http://test-server; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 必须配置: proxy_set_header X-Forwarded-Proto $scheme; # 作用是对发送给客户端的URL进行修改, 将http协议强制转为https proxy_redirect http:// https://; }
为了方便测试proxy_redirect
强制转换, http(80)、https(443)共存
server { listen 80; listen 443 ssl; ... }
重定向测试
-
JAVA CODE:
- HttpServletResponse resp = (HttpServletResponse)response;
- resp.sendRedirect("/static/html/index.html");
使用HTTP
协议访问nginx
代理地址之后,URL被重定向为HTTPS
协议了, 如下图所示:
当然直接使用HTTPS协议访问, 肯定也是没有问题的,如下图所示:
转发测试
-
JAVA CODE:
- HttpServletResponse resp = (HttpServletResponse)response;
- req.getRequestDispatcher("/static/html/index.html").forward(request, response);
测试结果与重定向一致, 无异常情况;
测试总结
实际应用场景中,如果要求HTTP
与HTTPS
协议共存的时候(请求的协议与响应的协议一致)就会出现HTTP
请求被强转为HTTPS
,尝试将Nginx配置proxy_redirect http:// https://;
注释,最终使用HTTPS
协议亦无法正常跳转;
实践二:Tomcat新增配置
不修改Nginx的情况下, 仅对Tomcat配置进行调整
在server.xml
的Engine
模块下面配置多一个以下的Valve
- <Valve className="org.apache.catalina.valves.RemoteIpValve"
- remoteIpHeader="X-Forwarded-For"
- protocolHeader="X-Forwarded-Proto"
- protocolHeaderHttpsValue="https"/>
重定向测试
使用HTTPS
协议访问时,最终被重定向到HTTP
转发测试
使用HTTPS
协议访问,转发动作未出现问题
测试总结
重定向的时候, HTTPS
协议被转为HTTP
,测试结果不通过。
实践三:终极方案
Nginx 配置
对过程一Nginx配置进行调整注释或删除proxy_redirect
,最终如下:
location / { proxy_pass http://test-server; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 必须配置: proxy_set_header X-Forwarded-Proto $scheme; }
Tomcat 配置
参看:Tomcat配置
测试过程
HTTP协议请求
HTTPS协议请求
测试结果
测试通过,无论使用HTTP访问还是HTTPS访问,最终返回都是根据请求的协议进行响应,问题解决。
完整配置
- Nginx
worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream test-server { server 10.15.16.6:8280 weight=1; } server { listen 80; listen 443 ssl; server_name localhost; #ssl_certificate cert.pem; #ssl_certificate_key cert.key; ssl_certificate server.crt; ssl_certificate_key server.key; # ssl_session_cache shared:SSL:1m; #ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; location / { proxy_pass http://test-server; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # proxy_redirect http:// https://; } } }
//处理代码段
- domainName = request.getRequestURL().toString();
- String X_Forwarded_Proto = httpRequest.getHeader("X-Forwarded-Proto");
- if(StringUtils.isNotBlank(X_Forwarded_Proto)){
- if(X_Forwarded_Proto.toLowerCase().contains("https") && !domainName.toLowerCase().startsWith("https://")){
- domainName = "https://" + domainName.substring(7);
- }
- }