SpringBoot整合WebSocket详解
环境:Springboot3.0.5
WebSocket介绍
WebSocket协议RFC 6455提供了一种标准化的方式,通过一个TCP连接在客户端和服务器之间建立全双工、双向的通信通道。它是一个不同于HTTP的TCP协议,但设计为在HTTP之上工作,使用80和443端口,并允许重用现有的防火墙规则。
WebSocket交互开始于一个HTTP请求,使用HTTP Upgrade header进行升级,在本例中是切换到WebSocket协议。下面的例子展示了这种交互:
GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: websocket // ①
Connection: Upgrade // ②
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080
①:Upgrade header头部信息
②:使用 Upgrade 连接
支持WebSocket的服务器会返回类似下面的输出,而不是通常的200状态码:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp
握手成功后,HTTP upgrade请求的TCP套接字保持打开,客户端和服务器可以继续发送和接收消息。
如果WebSocket服务器运行在web服务器(例如nginx)后面,你可能需要配置它来将WebSocket升级请求传递给WebSocket服务器。同样,如果应用程序运行在云环境中,请查看云提供商提供的有关WebSocket支持的说明。
HTTP与WebSocket
尽管WebSocket在设计上是与HTTP兼容的,而且从HTTP请求开始,但重要的是要明白,这两种协议导致了非常不同的架构和应用程序编程模型。
在HTTP和REST中,应用程序被建模为多个url。为了与应用程序交互,客户端以请求-响应的方式访问这些url。服务器根据HTTP URL、方法和首部将请求路由到适当的处理程序。
相比之下,在websocket中,初始连接通常只有一个URL。随后,所有应用程序消息都在同一个TCP连接上流动。这是一种完全不同的异步、事件驱动的消息传递架构。
WebSocket也是一种底层传输协议,与HTTP不同,它对消息内容没有任何语义规定。这意味着除非客户端和服务器在消息语义上达成一致,否则无法路由或处理消息。
WebSocket客户端和服务器可以通过HTTP握手请求的Sec-WebSocket-Protocol头部来协商使用更高级别的消息传递协议(例如STOMP)。在这种情况下,他们需要制定自己的惯例。
什么时候该使用WebSocket
WebSockets可以使网页具有动态性和交互性。然而,在许多情况下,Ajax和HTTP流或长轮询的组合可以提供简单而有效的解决方案。
例如,新闻、邮件和社交源需要动态更新,但每隔几分钟更新一次完全没问题。另一方面,协作、游戏和金融应用需要更接近实时。
延迟本身并不是决定性因素。如果消息量相对较少(例如监视网络故障),HTTP流或轮询可以提供有效的解决方案。低延迟、高频率和高容量的组合才是WebSocket的最佳选择。
还要记住,在互联网上,你无法控制的限制性代理可能会阻止WebSocket交互,要么是因为它们没有配置为传递Upgrade header,要么是因为它们关闭了看起来空闲的长连接。这意味着对防火墙内的内部应用程序使用WebSocket比面向公众的应用程序更直接。
WebSocket核心API
Spring框架提供了一个WebSocket API,可以用它来编写处理WebSocket消息的客户端和服务器端应用程序。
-
WebSocketHandler
创建WebSocket服务器很简单,只需实现WebSocketHandler,或者扩展TextWebSocketHandler或BinaryWebSocketHandler。下面的例子使用了TextWebSocketHandler:
public class MessageHandler extends TextWebSocketHandler {@Overridepublic void handleTextMessage(WebSocketSession session, TextMessage message) {System.out.printf("SessionId: %s, 接收到消息: %s%n", session.getId(), message.getPayload()) ;try {session.sendMessage(new TextMessage("服务端接收到消息 - " + message.getPayload())) ;} catch (IOException e) {e.printStackTrace();}}@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {System.out.printf("连接成功, 会话Id: %s, Attribute: %s%n", session.getId(), session.getAttributes()) ;}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {System.out.printf("连接关闭, 会话Id: %s, 关闭状态: %s%n", session.getId(), status.getCode() + " - " + status.getReason()) ;}}
WebSocket配置
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(messageHandler(), "/message")}@Beanpublic WebSocketHandler messageHandler() {return new MessageHandler();}
}
-
WebSocket Handshake
要定制初始的HTTP WebSocket握手请求,最简单的方法是使用HandshakeInterceptor,它提供了握手前和握手后的方法。你可以使用这样的拦截器来阻止握手,或者让 WebSocketSession可以访问任何属性。下面的例子使用内置的拦截器将HTTP会话属性传递给WebSocket会话:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(messageHandler(), "/message").setHandshakeHandler(handshakeHandler())// 添加捂手拦截器.addInterceptors(new HandshakeInterceptor() {// 如果该方法返回false,则不允许建立连接@Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {// todoattributes.put("uid", uid) ;return true ;}@Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,Exception exception) {// todo}}) ;}
}
-
部署
Spring WebSocket API很容易集成到Spring MVC应用程序中,DispatcherServlet可以同时处理HTTP WebSocket握手和其他HTTP请求。调用
WebSocketHttpRequestHandler也很容易集成到其他HTTP处理场景中。这样既方便又容易理解。但是,对于JSR-356运行时,需要特别注意。
Java WebSocket API (JSR-356)提供两种部署机制。第一种方法涉及启动时的Servlet容器类路径扫描(Servlet 3特性)@ServerEndpoint。另一个是Servlet容器初始化时使用的注册 API(
ServletContainerInitializer)。这两种机制都不可能对所有HTTP处理使用单个“前端控制器” — 包括WebSocket握手和所有其他HTTP请求 — 如Spring MVC的DispatcherServlet。
这是JSR-356的一个重要限制,Spring的WebSocket支持通过特定于服务器的RequestUpgradeStrategy实现来解决这个问题,即使运行在JSR-356运行时也是如此。Tomcat、Jetty、GlassFish、WebLogic、WebSphere和Undertow(以及WildFly)目前都存在这样的策略。
-
服务配置
每个底层WebSocket引擎都公开了控制运行时特征的配置属性,例如消息缓冲区大小、空闲超时等。
对于Tomcat、WildFly和GlassFish,可以在WebSocket Java配置中添加
ServletServerContainerFactoryBean,如下面的例子所示:
@Bean
public ServletServerContainerFactoryBean servletServerContainerFactoryBean() {ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean() ;container.setMaxTextMessageBufferSize(8192) ;container.setMaxBinaryMessageBufferSize(8192) ;return container ;
}
-
允许的来源
从Spring Framework 4.1.5开始,WebSocket和SockJS的默认行为是只接受同源请求。也可以允许所有或指定的来源列表。这个检查主要是为浏览器客户端设计的。没有什么能阻止其他类型的客户端修改Origin首部值。
三种可能的行为是:
-
仅允许同源请求(默认):在这种模式下,当启用SockJS时,Iframe HTTP响应头X-Frame-Options设置为SAMEORIGIN,并且禁用JSONP传输,因为它不允许检查请求的来源。因此,启用此模式时,不支持IE6和IE7。
-
允许指定的来源列表:每个允许的来源必须以http://或https://.开头在此模式下,当启用SockJS时,禁用IFrame传输。因此,启用此模式时,将不支持IE6到IE9。
-
允许所有来源:要启用此模式,你应该提供*作为允许的来源值。在该模式下,所有传输通道都可用。
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(messageHandler(), "/message").setAllowedOriginPatterns("*") ;}
}
测试
通过上面的介绍和配置,WebSocket环境就算是简单的配置完成了,接下来通过Postman进行测试。
连接成功
发送消息及接收消息
服务端接收到消息
完毕!!!
求助三连~~~
相关文章:

SpringBoot整合WebSocket详解
环境:Springboot3.0.5 WebSocket介绍 WebSocket协议RFC 6455提供了一种标准化的方式,通过一个TCP连接在客户端和服务器之间建立全双工、双向的通信通道。它是一个不同于HTTP的TCP协议,但设计为在HTTP之上工作,使用80和443端口&am…...

伪原创神码ai怎么样【php源码】
这篇文章主要介绍了python汉化补丁包下载,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。 火车头采集ai伪原创插件截图: ** Spyder汉化(python汉化&…...

Air001基于Keil环境开发,使用airisp串口命令行烧录
Air001基于Keil环境开发,使用airisp串口命令行烧录 有人会有这样的疑惑,使用Keil平台开发,为什么不直接使用CMSIS-DAP直接烧录,还要使用串口方式来去单独烧录,不是我不想,目前使用合宙官方的Air103芯片版本…...
kubernetes 中的事件(event)简介以及如何收集event和基于event告警
引用另外一篇文章对k8s event的介绍 1.什么是kubernetes事件 Kubernetes Events 是一种 Kubernetes 资源对象,记录了某个组件在某个时间做了某个动作,用于展示集群内发生的情况,当 Kubernetes 集群中资源状态发生变化时,可以产生…...

C++小游戏贪吃蛇源码
graphics.h是针对DOS下的一个C语言图形库 (c也可以) 目前支持下载此头文件的常用的有两种: 1. EGE (Easy Graphics Engine)2. EasyX Graphics LibraryEGE, 全名Easy Graphics Engine, 是windows下的简易绘图库,是一个类似BGI(graphics.h)的面向C/C语言新手的图形库…...
【密码学】穴居人密码
穴居人密码 文字记载中,有时会把来自古希腊文化之前的各种记录作为密码学的例子,但称它们为密码学一定太不严格了,这是因为那些方法都太原始了。密码学的起源能追溯到多早,取决于你把密码学的相关定义确定得有多宽泛。大多数作者都…...

neo4j的CQL命令实例演示
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...

vue3+ts使用antv/x6
使用 2.x 版本 x6.antv 新官网: 安装 npm install antv/x6 //"antv/x6": "^2.1.6",项目结构 1、初始化画布 index.vue <template><div id"container"></div> </template><script setup langts> import { onM…...
wsl1 ubuntu通过宿主机代理连接外网
文章目录 环境变量配置apt换源apt安装,测试是否能通外网可能出现的问题:Temporary failure resolving 参考 背景:公司电脑是局域网,通过走代理来连接外网 wsl1 ubuntu想要通过来连接宿主机的局域网代理,访问外网 可以…...
ubuntu20.04 opencv4.2 安装笔记
参考: https://docs.opencv.org/4.x/d7/d9f/tutorial_linux_install.html Build with opencv_contrib # 1. Install minimal prerequisites, libgtk2.0-dev pkg-config 用来显示图像 sudo apt update && sudo apt install -y cmake g wget un…...

ubuntu安装nginx以及php的部署
目录 1.安装依赖包 2.安装nginx 3.编译nginx 4.启动nginx 5.访问nginx 6.增加源地址 7.安装php 8.配置php-fpm 9.修改权限 10.配置nginx里的php 11.启动php-fpm 12.配置php文件以及权限 13.登陆查看 1.安装依赖包 apt-get install gcc apt-get install libpcre3 l…...

IntelliJ IDEA 2021/2022关闭双击shift全局搜索
我这里演示的是修改,删除是右键的时候选择Remove就好了 IDEA左上角 File-->Settings 找到Navigate -->Search Everywhere ,右键添加快捷键。 OK --> Apply应用...
HTML 元素中的name 属性
name 属性是 HTML 元素中常用的属性之一。它用于指定表单元素的名称,以便在提交表单时将其值与对应的键关联起来。 每个表单元素(例如 <input>、<select> 和 <textarea>)都可以具有一个 name 属性,该属性为元素…...

快速上手React:从概述到组件与事件处理
前言 「作者主页」:雪碧有白泡泡 「个人网站」:雪碧的个人网站 「推荐专栏」: ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄,vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄ÿ…...

K8S系列文章之 离线安装自动化工具Ansible
参考 文档 离线安装 Ansible - DevOps - dbaselife 一、Ansible简介 Ansible是一款开源的IT配置管理工具,常被IT界的小伙伴们用于自动化的场景,多用在服务部署、配置管理方面。配置文件采用最常见的yaml格式,学习起来也是比较容易ÿ…...
mysql8.0.3集群搭建
下载mysql安装包: https://dev.mysql.com/downloads/mysql/5.7.html#downloads 准备环境 1、准备三台服务器并设置hosts 192.168.236.143 mysql1 192.168.236.144 mysql2 192.168.236.145 mysql32、设置免密登陆 #生成秘钥 ssh-keygen -t rsa #一直按Enter即可…...
vue中router路由的原理?两种路由模式如何实现?(vue2) -(上)
平时我们编写路由时,通常直接下载插件使用,在main.js文件中引入直接通过引入vue-router中的Router通过Vue.use使用以后定义一个routeMap数组,里边是我们编写路由的地方,最后通过实例化一个 Router实例 将routes我们定义的routeMao…...

消息队列(3) -封装数据库的操作
前言 上一篇博客我们写了, 关于交换机, 队列,绑定, 写入数据库的一些建库建表的操作 这一篇博客中,我们将建库建表操作,封装一下实现层一个类来供上层服务的调用 , 并在写完该类之后, 测试代码是否完整 实现封装 在写完上述的接口类 与 xml 后, 我们想要 创建一个类 ,来调用…...

PostgreSQL中根据时间段范围查询数据,如19:29:10到20:29:10范围内的数据,排除年月日
数据格式如下 问题描述 我的SQL语句条件是 WHERE (TO_CHAR(cti.binder_gen_time, YYYY-MM-DD HH:mm:ss) > 19:29:10 AND TO_CHAR(cti.binder_gen_time, YYYY-MM-DD HH:mm:ss) < 20:29:10)为什么我数据的时间是2023-07-20 17:58:29也能被查出来? 问题解决…...

【二分+贪心】CF1665 C
Problem - C - Codeforces 题意: 思路: 一开始想太简单wa6了 只想到先感染大的分量,然后最后把最大的分量剩下的染色 但是可能会有别的分量更大(因为最后给最大的染色之后可能不再是最大的) 可以用堆维护…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...