SpringCloud网关 SpringBoot服务 HTTP/HTTPS路由/监听双支持
背景
一般来说SpringCloud Gateway到后面服务的路由属于内网交互,因此路由方式是否是Https就显得不是那么重要了。事实上也确实如此,大多数的应用开发时基本都是直接Http就过去了,不会一开始就是直接上Https。然而随着时间的推移,项目规模的不断扩大,当被要求一定要走Https时,就会面临一种困惑:将所有服务用一刀切的方式改为Https方式监听,同时还要将网关服务所有的路由方式也全部切为Https方式,一旦生产环境上线出问题将要面临全量服务的归滚,这时运维很可能跳出来说:生产环境几十个服务,每个服务最少2个节点,全量部署和回滚不可能在短时间完成。另外测试同学也可能会说,现在没有全量接口自动化回归测试工具,做一个次人工的全量接口回归测试也不现实。因此在这种情况下最稳妥的方式是实现:SpringCloud Gateway & SpringBoot RestController Http/Https双支持,这样可以做到分批分次进行切换,那么上面的困惑自然也就不存在了。
1. SpringBoot Http/Https监听双支持
1.1 代码实现
为了不对原来的Http监听产生任何影响,因此需要保障以下两点:
1、原主端口(server.port)监听什么都不变,监听方式仍为http,附加端口监听方式为https。(需要绕开的问题是:如果一个服务有多个监听端口,主端口会优先选择https方式)
2、附加端口不进行nacos服务注册(主要的考虑点还是不对原来的http监听和路由产生任何影响,这里我的方案是https监听端口号为http端口+10000)。
这样就能实现SpringBoot服务主端口Http监听,附加端口Https监听。
实现代码如下:
import org.apache.catalina.connector.Connector;
import org.apache.coyote.http11.Http11NioProtocol;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** HttpsConnectorAddInConfiguration** @author chenx*/
@Configuration
public class HttpsConnectorAddInConfiguration {private static final int HTTPS_PORT_OFFSET = 10000;@Value("${server.port}")private int port;@Value("${additional-https-connector.ssl.key-store:XXX.p12}")private String keyStore;@Value("${additional-https-connector.ssl.key-store-password:XXX}")private String keyStorePassword;@Value("${additional-https-connector.ssl.key-store-type:PKCS12}")private String keyStoreType;@Value("${additional-https-connector.ssl.enabled:false}")private boolean enabled;@Beanpublic WebServerFactoryCustomizer<TomcatServletWebServerFactory> servletContainer() {return server -> {if (!this.enabled) {return;}Connector httpsConnector = this.createHttpsConnector();server.addAdditionalTomcatConnectors(httpsConnector);};}/*** createHttpsConnector** @return*/private Connector createHttpsConnector() {Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);connector.setScheme("https");connector.setPort(this.port + HTTPS_PORT_OFFSET);connector.setSecure(true);Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();protocol.setSSLEnabled(true);protocol.setKeystoreFile(this.keyStore);protocol.setKeystorePass(this.keyStorePassword);protocol.setKeystoreType(this.keyStoreType);protocol.setSslProtocol("TLS");return connector;}
}
备注:
1、上述代码中的配置默认值大家自行修改(key-store:XXX.p12,key-store-password:XXX),如果觉得配置additional-https-connector相关配置命名不合适也可自行修改。当配置好additional-https-connector相关配置(additional-https-connector.ssl.enabled是一个https附加端口监听的开关),启动服务就可以看到类似如下的日志,同时查看nacos中的服务实例也会发现并没有进行https端口的服务注册;
2、这里我用的是p12自签证书,证书需要放到项目的resouces目录下(可以用keytool -genkey命令去生成一个)。
1.2 配置
配置示例如下,keyStore、keyStorePassword、keyStoreType使用代码中的默认值,需要更换证书的时候再进行配置。
server:port: 9021tomcat:min-spare-threads: 400max-threads: 800additional-https-connector:ssl:enabled: true
2. SpringCloud Gateway Http/Https路由双支持
思路:在网关服务增加自定义配置(HttpsServiceConfig)来定义需要切换为https路由的服务列表,然后使用过滤器(HttpsLoadBalancerFilter)进行转发uri的https重写;
这样就能实现在配置列表中的服务进行Https路由,否则保持原有Https路由。
2.1 代码实现
- HttpsServiceConfig
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.endpoint.event.RefreshEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;import java.util.HashSet;
import java.util.List;
import java.util.Set;/*** HttpsServiceConfig** @author chenx*/
@Slf4j
@Component
@RefreshScope
@ConfigurationProperties(prefix = "bw.gateway")
public class HttpsServiceConfig {private List<String> httpsServices;private Set<String> httpsServiceSet = new HashSet<>();public List<String> getHttpsServices() {return this.httpsServices;}public void setHttpsServices(List<String> httpsServices) {this.httpsServices = httpsServices;this.updateHttpsServices();}public Set<String> getHttpsServiceSet() {return this.httpsServiceSet;}/*** handleRefreshEvent*/@EventListener(RefreshEvent.class)public void handleRefreshEvent() {this.updateHttpsServices();}/*** updateHttpsServices*/private void updateHttpsServices() {this.httpsServiceSet = CollectionUtils.isNotEmpty(this.httpsServices) ? new HashSet<>(this.httpsServices) : new HashSet<>();log.info("httpsServiceSet updated, httpsServiceSet.size() = {}", this.httpsServiceSet.size());}
}
- HttpsLoadBalancerFilter
import com.beam.work.gateway.common.FilterEnum;
import com.beam.work.gateway.config.HttpsServiceConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;import java.net.URI;
import java.util.Objects;/*** HttpsLoadBalancerFilter** @author chenx*/
@Slf4j
@RefreshScope
@Component
public class HttpsLoadBalancerFilter implements GlobalFilter, Ordered {private static final int HTTPS_PORT_OFFSET = 10000;private final LoadBalancerClient loadBalancer;@Autowiredprivate HttpsServiceConfig httpsServiceConfig;public HttpsLoadBalancerFilter(LoadBalancerClient loadBalancer) {this.loadBalancer = loadBalancer;}@Overridepublic int getOrder() {return FilterEnum.HTTPS_LOAD_BALANCER_FILTER.getCode();}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);boolean isRewriteToHttps = Objects.nonNull(route) && this.httpsServiceConfig.getHttpsServiceSet().contains(route.getId());if (isRewriteToHttps) {ServiceInstance instance = this.loadBalancer.choose(route.getUri().getHost());if (Objects.nonNull(instance)) {URI originalUri = exchange.getRequest().getURI();URI httpsUri = UriComponentsBuilder.fromUri(originalUri).scheme("https").host(instance.getHost()).port(instance.getPort() + HTTPS_PORT_OFFSET).build(true).toUri();log.info("HttpsLoadBalancerFilter RewriteToHttps: {}", httpsUri.toString());exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, httpsUri);}}return chain.filter(exchange);}
}
备注:
1、这里实现了配置的刷新,因此需要进行服务的https路由切换时只需修改配置即可,而网关服务不需要重启;
2、过滤器使用Set进行判断,效率上肯定优于对List的遍历查找;
3、过滤器的Order建议放到最后,因此可以直接使用Integer.MAX_VALUE(我们的项目中有多个过滤器,并且通过FilterEnum枚举去统一管理);
2.2 配置
配置示例:
spring:cloud:gateway:enabled: true httpclient:ssl:use-insecure-trust-manager: trueconnect-timeout: 10000response-timeout: 120000pool:max-idle-time: 15000max-life-time: 45000evictionInterval: 5000routes:- id: bw-star-favoriteuri: lb://bw-star-favoriteorder: -1predicates:- Path=/star-favoritear/v1/**bw:gateway:xssRequestFilterEnable: falsexssResponseFilterEnable: falsehttpsServices:- bw-star-favorite
备注:
1、需要变更的配置为:
- 开启ssl信任(spring.cloud.gateway.httpclient.ssl):
- 设置https路由服务列表(bw.gateway.httpsServices)
结束语
通过上述两步就能实现SpringCloud Gateway & SpringBoot RestController Http/Https双支持,严谨的做法是还需要将FeignClient的调用进行Https化,上面的实现方式中之所以不对https端口进行注册的原因就是避免Http方式的FeignClient去调用Https目标端口从而引发问题。关于FeignClient的Https切换实际上也可以借鉴网关的思路将请求uri重写为端口号+10000的https请求即可。
那么通过这个思路就可以实现:服务的分批、FeignClient分步Https路由切换,从而保障整个割接风险可控和平滑。
相关文章:

SpringCloud网关 SpringBoot服务 HTTP/HTTPS路由/监听双支持
背景 一般来说SpringCloud Gateway到后面服务的路由属于内网交互,因此路由方式是否是Https就显得不是那么重要了。事实上也确实如此,大多数的应用开发时基本都是直接Http就过去了,不会一开始就是直接上Https。然而随着时间的推移,…...

JavaScript做网页是否过期的处理
通过路由上的参数生成唯一md5和路由上token做验证_md5 token-CSDN博客 前言:基于这篇文章我们做网页是否超时,网页是否过期的处理。打开一个网页允许他在一定时间内可以访问,过了这个时间就不可以访问了,encrypt是h5加密方法&…...
python coding时遇到的问题
Q:只有cpu的时候加载模型 A:checkpoint torch.load(model_path, map_locationtorch.device(‘cpu’)) Q:vscode的文件路径和spyder的不一样 A:在vscode中,右键要用的文件,选择“文件相对路径”...

攻防演练号角吹响,聚铭铭察高级威胁检测系统助您零失分打赢重保攻坚战
在数字化浪潮中,攻防演练成为了衡量网络安全防御力的核心标尺,其重要性与日俱增。这项由政府、行业监管或企业内部主导的安全活动,随着互联网普及而兴起,现已发展成为全球公认的检验网络安全体系效能的标准。它不仅关乎技术实力的…...

个人量化交易兴起!有什么好用的量化软件推荐?迅投QMT量化平台简介!
QMT是专门为机构、活跃投资者、高净值客户等专业投资者研发的智能量化交易终端,拥有高速行情、极速交易、策略交易、多维度风控等专业功能,满足专业投资者的特殊交易需求。覆盖业务范围广:沪深A股、港股通、两融、期权、期货。 适合用QMT的投资者&#x…...

SQL labs-SQL注入(七,sqlmap对于post传参方式的注入,2)
本文仅作为学习参考使用,本文作者对任何使用本文进行渗透攻击破坏不负任何责任。参考:SQL注入之Header注入_sqlmap header注入-CSDN博客 序言: 本文主要讲解基于SQL labs靶场,sqlmap工具进行的post传参方式的SQL注入,…...

SAM 2: Segment Anything in Images and Videos
Introduction 提出的目的: 1.现有的应用像自动驾驶,AR等来说都是需要temporal localization beyond image-level segmentation(时序定位而不仅是图片分割) 2. 一个好的分割模型不应该仅仅局限于图片领域,而是图视频两…...

软件测试面试,如何自我介绍?
又是一年金九银十,相信不少小伙伴都在准备跳槽面试,而面试中一个必不可少的环节就是自我介绍,所以,今天我们就来聊一聊软件测试面试中如何自我介绍。 为什么要自我介绍 在讨论如何自我介绍之前,我们先来讨论一下为…...
力扣第四十七题——全排列II
内容介绍 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。 示例 1: 输入:nums [1,1,2] 输出: [[1,1,2],[1,2,1],[2,1,1]]示例 2: 输入:nums [1,2,3] 输出:[[1,2,3],…...

Springer旗下中科院2区TOP,国人优势大!
关注GZH【欧亚科睿学术】,第一时间了解期刊最新动态! 1 通信网络类 【期刊简介】IF:4.0-5.0,JCR1区,中科院3区 【出版社】ELSEVIER出版社 【检索情况】SCIE&EI双检,CCF-C类 【征稿领域】通信网络的…...

【C++】C++入门知识详解(下)
大家好~我们接着【C】C入门知识详解(上)-CSDN博客来介绍另一些C入门基础知识。 1.缺省值和缺省参数 缺省参数就是声明或定义函数时为函数的参数指定一个缺省参数。在调用该函数时,如果没有指定实参,则采用该形参的缺省值…...
分压电阻方式的ADC电压校准
无人机有个流程是电池电压校准。具体做法是:让你用万用表测量一下电池两端的电压,然后输入到文本框中,电机计算能重新计算出电压分压器的值,从而获得电池电压值。 这种方法实现的原理是这样的: 电阻分压检测电压原理,以上图为例: 当电路确定时,R2/(R1+R2)是一个定值R,…...
使用Postman测试API短轮询机制:深入指南
短轮询是一种Web开发中常用的技术,用于在客户端和服务器之间定期检查更新。与长轮询或WebSockets等技术相比,短轮询简单易实现,但可能带来较多的HTTP请求,从而增加服务器负担。Postman作为一个强大的API测试工具,可以用…...

明清进士人数数据
明清进士人数数据 指标:省份名称、城市名称、区县名称、明清各省进士人数、明清各城市进士人数、明清各县区进士人数 指标说明: Province[省份名称]-统计数据所属省份 City[城市名称]-统计数据所属地级市 Region[区县名称]-统计数据所属区县 MQpro…...

C# 串口通信(通过serialPort控件发送及接收数据)
连接串口 界面设计打开串口发送数据通过文件发送发送数据 接收数据 首先可以在 工具箱中搜索serialport,将控件拖到你的Winfrom窗口。 界面设计 打开串口 private void Connect_Click(object sender, EventArgs e){serialPort1.PortName comboBox2.Text;//端口名s…...
数据安全的新盾牌:SQL Server数据库镜像技术详解
数据安全的新盾牌:SQL Server数据库镜像技术详解 在数据驱动的商业世界中,数据库的安全性是维护企业运营的关键。SQL Server提供了多种数据保护机制,其中数据库镜像技术是一个强大的高可用性解决方案,它可以显著提高数据的安全性…...

【C语言版】数据结构教程(一)绪论(上)
【内容简介】本文整理数据结构(C语言版)相关内容的复习笔记,供各位朋友借鉴学习。本章内容更偏于记忆和理解,请读者们耐心阅读。 数据结构教程 绪论(上) 本节学习目标 1.1 基本概念 1.2 抽象数据类型的表示…...
酒后为什么总感觉渴?
喝酒后感到口渴,这种感觉其实很常见。这主要是因为酒精对我们的身体有几种影响。首先,酒精能够扩张血管,这会加快血液循环,让肾脏更加活跃,产生更多的尿液。这样一来,我们体内的水分就会通过排尿流失&#…...

Docker安装OwnCloud私有云盘对接ceph
一、安装OwnCloud 我的安装包链接:https://pan.baidu.com/s/1cJO8WEonsw4gGQWgQaYzpw?pwd6bak 提取码:6bak 启动OwnCloud容器,没有镜像会自动下载 docker run -d -p 80:80 -v /home/owncloud:/var/www/html --name owncloud --restartalway…...

创建了Vue项目,需要导入什么插件以及怎么导入
如果你不知道怎么创建Vue项目,建议可以看一看这篇文章 怎么安装Vue的环境和搭建Vue的项目-CSDN博客 1.在idea中打开目标文件 2.系在一个插件Vue.js 3.下载ELement UI 在Terminal中输入 # 切换到项目根目录 cd vueadmin-vue # 或者直接在idea中执行下面命令 # 安装element-u…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...

论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving
地址:LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂,正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...