Spring Gateway转发websocket原理

Spring Cloud Gateway简称Spring Gateway,它可以转发请求到后端微服务。Spring Gateway除了转发HTTP请求,也支持websocket请求。我们看下它是怎么实现的吧。

配置支持websocket转发

支持websocket转发,需要用到spring-cloud-starter-gateway ,不要搞错成spring-cloud-starter-gateway-web 。引入maven配置:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId><version>4.1.4</version>
</dependency>

然后注册需要路由的规则,可以通过yml配置。

spring:cloud:gateway:routes:- id: ws1uri: ws://localhost:8080predicates:- Path=/ws

Java配置方式,与yml方式等效。

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {return builder.routes().route("ws1", r -> r.path("/ws").uri("ws://localhost:8080")).build();
}

websocket转发原理

处理websocket协议转发的类是org.springframework.cloud.gateway.filter.WebsocketRoutingFilter。它的filter方法会过滤出ws和wss两类请求。

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {changeSchemeIfIsWebSocketUpgrade(exchange);URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);String scheme = requestUrl.getScheme();if (isAlreadyRouted(exchange) || (!"ws".equals(scheme) && !"wss".equals(scheme))) {return chain.filter(exchange);}setAlreadyRouted(exchange);HttpHeaders headers = exchange.getRequest().getHeaders();HttpHeaders filtered = filterRequest(getHeadersFilters(), exchange);List<String> protocols = getProtocols(headers);return this.webSocketService.handleRequest(exchange,new ProxyWebSocketHandler(requestUrl, this.webSocketClient, filtered, protocols));
}

可以看到方法的最后一行的handleRequest()方法,exchange是当前发给网关的ws握手请求,ProxyWebSocketHandler用来处理网关和客户端建立完websocket链接成功后的事件。重点看看ProxyWebSocketHandler的handle()方法。


@Override
public Mono<Void> handle(WebSocketSession session) {// pass headers along so custom headers can be sent throughreturn client.execute(url, this.headers, new WebSocketHandler() {// 省略部分代码... });
}

handle()方法里用client(WebSocketClient )给后端websocket地址发来一个握手请求。

到这里,网关握手的流程就清晰了。前端客户端 —[连接]—>网关—[连接]—>后端websocket服务,总共会产生2条websocket连接。

然后就是发消息和断开连接的方式,就在上面省略代码里。

new WebSocketHandler() {@Overridepublic Mono<Void> handle(WebSocketSession proxySession) {Mono<Void> serverClose = proxySession.closeStatus().filter(__ -> session.isOpen()).map(this::adaptCloseStatus).flatMap(session::close);Mono<Void> proxyClose = session.closeStatus().filter(__ -> proxySession.isOpen()).map(this::adaptCloseStatus).flatMap(proxySession::close);// Use retain() for Reactor NettyMono<Void> proxySessionSend = proxySession.send(session.receive().doOnNext(WebSocketMessage::retain).doOnNext(webSocketMessage -> {if (log.isTraceEnabled()) {log.trace("proxySession(send from client): " + proxySession.getId()+ ", corresponding session:" + session.getId() + ", packet: "+ webSocketMessage.getPayloadAsText());}}));// .log("proxySessionSend", Level.FINE);Mono<Void> serverSessionSend = session.send(proxySession.receive().doOnNext(WebSocketMessage::retain).doOnNext(webSocketMessage -> {if (log.isTraceEnabled()) {log.trace("session(send from backend): " + session.getId()+ ", corresponding proxySession:" + proxySession.getId() + " packet: "+ webSocketMessage.getPayloadAsText());}}));// .log("sessionSend", Level.FINE);// Ensure closeStatus from one propagates to the otherMono.when(serverClose, proxyClose).subscribe();// Complete when both sessions are donereturn Mono.zip(proxySessionSend, serverSessionSend).then();}
}

websocket连接关闭,是serverClose和proxyClose这两行代码,当后端的websocket连接断开时,就会把断开的转发设置到网关的websocket连接上;网关的websocket连接断开时,就会把断开的转发设置到后端的websocket连接上。这样,两个websocket连接的断开状态就一致了。

websocket发送消息,是proxySessionSend和serverSessionSend这两行代码,当网关收到客户端消息时,就会把消息发送给后端websocket服务;当网关收到后端websocket发来的消息时,就会把消息转发给客户端。

至此,网关在websocket连接、发消息、断开连接就和后端websocket服务保持一致了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/32407.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高通安卓12-OTA 升级

1.OTA介绍 OTA 英文全称是 Over-the-Air Technology&#xff0c;即空间下载技术的意思。 OTA 升级是 Android 系统提供的标准软件升级方式。它功能强大&#xff0c;可以无损失升级系统&#xff0c;主 要通过网络[例如 WIFI、3G]自动下载 OTA 升级包、自动升级&#xff0c;但…

TCP协议详解:三次握手与四次挥手

TCP协议详解:三次握手与四次挥手 目录 TCP协议详解:三次握手与四次挥手 一、TCP协议概述 二、TCP连接建立:三次握手 三、TCP连接释放:四次挥手 四、TCP协议的可靠性机制 五、TCP流量控制与拥塞控制 一、TCP协议概述 TCP(传输控制协议)是一种面向连接的、可靠的、基于…

Windows11系统自动获取电脑IPV6地址,并且开机自动发送到指定邮箱

废话&#xff1a;最近放假回家&#xff0c;在家里突然想玩游戏了&#xff0c;Steamdeck性能终归有限。部分游戏始终玩的不爽&#xff0c;想到之前了解到的SunshnieMoonlight串流的方案&#xff0c;远程调用家里的电脑打游戏&#xff0c;简直不要太爽。 一顿折腾之后配置好了所有…

发送短信v2

接口说明 接口英文名 newSendCloudBaseSms 功能描述 发送携带 URL Link 的短信 注意事项 短信内容 短信由签名和正文内容组成&#xff1a; 短信签名是位于短信正文前【】中的署名&#xff0c;小程序发送短信时&#xff0c;签名为小程序名称。 正文内容是由短信模板和变…

【职场人】“万事皆可”领导的职场囧途

故事单元一&#xff1a;无所不能的承诺 在我的公司里&#xff0c;有一位领导&#xff0c;我们戏称他为“万事皆可”先生。每当有新的任务或挑战出现时&#xff0c;他总是第一个站出来&#xff0c;拍着胸脯说&#xff1a;“没问题&#xff0c;交给我吧&#xff01;”他的这种自…

一种微弱故障特征增强的旋转机械故障诊断方法(MATLAB)

导致轴承失效的根本原因是由异常磨损和局部间的机械冲击所导致的。对轴箱轴承日常运转的下所产生的均匀磨损而言&#xff0c;其振动信号特征与正常轴承振动信号大致一样&#xff0c;随机性较强&#xff0c;其概率密度函数呈现出高斯分布的现象&#xff0c;但由于磨损所导致的不…

37 - 上级经理已离职的公司员工(高频 SQL 50 题基础版)

37 - 上级经理已离职的公司员工 selecte1.employee_id fromEmployees e1 left join Employees e2 on e1.manager_id e2.employee_id wheree2.manager_id is null and e1.manager_id is not null and e1.salary<30000;

《计算机英语》 Unit 5 Networking 网络

Section A Networking 网络 The need to share information and resources among different computers has led to linked computer systems, called networks, in which computers are connected so that data can be transferred from machine to machine. 不同计算机之间共享…

什么是正态分布

最重要的连续分布的通用名是概率密度函数&#xff0c;而标准正态分布&#xff08;Standard Normal Distribution&#xff09; 是最重要的概率密度函数。这个连续分布之所以重要&#xff0c;我认为是因为它非常常见&#xff0c;换句话说&#xff0c;我们会很常用到它。标准正态分…

C++基础编程100题-012 OpenJudge-1.3-10 计算并联电阻的阻值

更多资源请关注纽扣编程微信公众号 http://noi.openjudge.cn/ch0103/09/ 描述 对于阻值为r1和r2的电阻&#xff0c;其并联电阻阻值公式计算如下&#xff1a; R 1/(1/r1 1/r2) 输入 两个电阻阻抗大小&#xff0c;浮点型&#xff0c;以一个空格分开。 输出 并联之后的阻…

【tomcat】tomcat系统架构以及核心启动流程

对于web后端开发工程师来说&#xff0c;tomcat作为一个应用服务器框架本质上就是一个HTTP服务Servlet容器。研究过spring、spring mvc源码的同学应该了解&#xff0c;spring mvc其实就是基于Servlet规范实现的请求的转发路由、转发处理。而Spring和SpringMVC就是通过web.xml文件…

如何在Java中使用正则表达式进行文本处理

如何在Java中使用正则表达式进行文本处理 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在Java编程中&#xff0c;正则表达式&#xff08;Regular Expressio…

python将音频文件从8kHz采样率转换为16kHz采样率,并保持双声道,立体声

要将音频文件从8kHz采样率转换为16kHz采样率&#xff0c;并保持双声道&#xff0c;可以使用Python中的pydub库&#xff0c;它简单易用&#xff0c;非常适合这类音频处理任务。但请注意&#xff0c;使用pydub之前需要确保你的系统中已安装ffmpeg&#xff0c;因为pydub依赖于ffmp…

Elasticsearch过滤器(Filter):原理及使用

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

Ruby编程语言学习

学习Ruby编程语言&#xff0c;你可以按照以下步骤进行&#xff1a; ### 1. 基础知识入门 #### 安装Ruby - 访问Ruby官网&#xff08;https://www.ruby-lang.org/&#xff09;下载适合你操作系统的版本。 - 对于Linux用户&#xff0c;可以使用包管理器安装。 #### 学习资源 -…

【MATLAB源码-第227期】基于matlab的北方苍鹰优化算法(NGO)机器人栅格路径规划,输出做短路径图和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 鼠群优化算法&#xff08;Rat Swarm Optimization, RSO&#xff09; 简介 鼠群优化算法&#xff08;Rat Swarm Optimization, RSO&#xff09;是一种模仿鼠类群体觅食行为的优化算法。该算法属于群体智能算法&#xff0c;通…

ElementPlus el-date-picker日期时间选择器组件禁用此刻之前的时间(精确时分秒)

需求&#xff1a;如上图所示&#xff0c;此刻之前的日期和时间都不可选&#xff0c;也就是选择当天的话需要限制时间选择器&#xff0c;如果选择的是今天之后的日期则不需要限制时间选择器。 实现思路 限制日期 使用DateTimePicker 日期时间选择器 的disabled-date 限制时间…

yolov8训练初体验

最近在爬一些数据&#xff0c;有些网址的验证码比较难搞&#xff0c;于是使用yolov8来解决。 一、数据打标签并转为txt 使用的软件为X-AnyLabeling。内置各种模型&#xff0c;方便打标。 打标完成后由于是json格式&#xff0c;所以我们使用python转换即可 import json import…

awdawdad

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;C 创作时间 &#xff1a;2024年6月20日 最后&#xff1a; 十分感谢你可以耐着性子把它读完和我可以坚持写到这里&#xff0c;送几句话&#xff0c;对你&#xff0c;也对我&#xff1a; 1.一个冷知识&#xff1a; …

阿赵UE引擎C++编程学习笔记——C++自定义蓝图函数

大家好&#xff0c;我是阿赵。   使用UE引擎&#xff0c;大部分功能都可以使用蓝图的自带节点去完成。但有时候我们也需要扩展一些蓝图没有的功能。这一篇主要学习一下怎样用C给蓝图新增自定义的函数节点。 一、 新建蓝图函数库 在添加C类的时候&#xff0c;选择蓝图函数库&…