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首部值。

三种可能的行为是:

  1. 仅允许同源请求(默认):在这种模式下,当启用SockJS时,Iframe HTTP响应头X-Frame-Options设置为SAMEORIGIN,并且禁用JSONP传输,因为它不允许检查请求的来源。因此,启用此模式时,不支持IE6和IE7。

  2. 允许指定的来源列表:每个允许的来源必须以http://或https://.开头在此模式下,当启用SockJS时,禁用IFrame传输。因此,启用此模式时,将不支持IE6到IE9。

  3. 允许所有来源:要启用此模式,你应该提供*作为允许的来源值。在该模式下,所有传输通道都可用。

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(messageHandler(), "/message").setAllowedOriginPatterns("*") ;}
}

图片

测试

通过上面的介绍和配置,WebSocket环境就算是简单的配置完成了,接下来通过Postman进行测试。

图片

连接成功

图片

发送消息及接收消息

图片

服务端接收到消息

完毕!!!

 求助三连~~~

 图片

 

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

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

相关文章

Excel革命,基于电子表格开发的新工具,不是Access和Power Fx

深谙其道 在日常工作中&#xff0c;Excel是许多人不可或缺的办公工具。 是微软的旗下产品&#xff0c;属于Microsoft 365套件中的一部分&#xff0c;强大的数据处理和计算功能&#xff0c;被普遍应用在全球各行各业的人群当中&#xff0c;是一款强大且普及的电子表格软件。 于…

Do not access Object.prototype method ‘hasOwnProperty‘ from target object

调用 hasOwnProperty 报错&#xff1a;不要使用对象原型上的方法&#xff0c;因为原型的方法可能会被重写 if (this.formData.selectFields.hasOwnProperty(selectField)) {delete this.formData.selectFields[selectField];} else {this.formData.selectFields[selectField] …

【FastColoredTextBox】C# 开源文本编辑控件

主界面截图 使用Demos演示 FastColoredTextBox 是一个用于在 C# 程序中实现高亮语法着色、代码编辑和文本显示的自定义控件。它提供了许多功能&#xff0c;包括&#xff1a; 语法高亮&#xff1a;FastColoredTextBox 支持多种语言的语法高亮&#xff0c;可以根据语法规则将不同…

安路FPGA的赋值报错——移位处理,加括号

authordaisy.skye的博客_CSDN博客-嵌入式,Qt,Linux领域博主 在使用移位符号用来当作除以号使用时&#xff0c;发现如下问题 其中 cnt_8K 为偶数和奇数时输出的数据不一样 reg [10:0] cnt_8K; reg [10:0] ram1_addra; always(posedge clk_16M) begin if(ram_out_flag )begin if(…

【Servlet】(Servlet API HttpServlet 处理请求 HttpServletRequest 打印请求信息 前端给后端传参)

文章目录 Servlet APIHttpServlet处理请求 HttpServletRequest打印请求信息前端给后端传参 Servlet API Servlet中常用的API HttpServlet 实际开发的时候主要重写 doXXX 方法, 很少会重写 init / destory / service destory 服务器终止的时候会调用. //下面的注解把当前类和…

【ARM】Day1

作业1&#xff1a;思维导图 作业2&#xff1a; 作业3&#xff1a;用for循环实现1~100之间和5050

ROS-PyQt小案例

前言&#xff1a;目前还在学习ROS无人机框架中&#xff0c;&#xff0c;&#xff0c; 更多更新文章详见我的个人博客主页【前往】 ROS与PyQt5结合的小demo&#xff0c;用于学习如何设计一个界面&#xff0c;并与ROS中的Service和Topic结合&#xff0c;从而控制多个小乌龟的运动…

事务和事务的隔离级别

1.4.事务和事务的隔离级别 1.4.1.为什么需要事务 事务是数据库管理系统&#xff08;DBMS&#xff09;执行过程中的一个逻辑单位&#xff08;不可再进行分割&#xff09;&#xff0c;由一个有限的数据库操作序列构成&#xff08;多个DML语句&#xff0c;select语句不包含事务&…

CSDN编程题-每日一练(2023-08-14)

CSDN编程题-每日一练&#xff08;2023-08-14&#xff09; 一、题目名称&#xff1a;小股炒股二、题目名称&#xff1a;王子闯闸门三、题目名称&#xff1a;圆小艺 一、题目名称&#xff1a;小股炒股 时间限制&#xff1a;1000ms内存限制&#xff1a;256M 题目描述&#xff1a; …

算法通关村第七关——递归和迭代实现二叉树前中后序遍历

1.递归 1.1 熟悉递归 所有的递归有两个基本特征&#xff1a; 执行时范围不断缩小&#xff0c;这样才能触底反弹。终止判断在调用递归的前面。 写递归的步骤&#xff1a; 从小到大递推。分情况讨论&#xff0c;明确结束条件。组合出完整方法。想验证就从大到小画图推演。 …

LinuxC编程——进程间通信(二)(信号、共享内存)

目录 一、信号1.1 概念1.2 信号的响应方式⭐⭐⭐1.3 几种常见的信号1.4 函数练习 二、共享内存2.1 共享内存的特点2.2 共享内存创建步骤⭐⭐2.3 共享内存创建所需函数 信号主要用来通知进程异步事件的发生。最初信号设计的目的是为了处理错误&#xff0c;它们也用来作为最基本的…

【设计模式】前端控制器模式

前端控制器模式&#xff08;Front Controller Pattern&#xff09;是用来提供一个集中的请求处理机制&#xff0c;所有的请求都将由一个单一的处理程序处理。该处理程序可以做认证/授权/记录日志&#xff0c;或者跟踪请求&#xff0c;然后把请求传给相应的处理程序。以下是这种…

Java Review - 关于代理的二三事儿

文章目录 Pre概述静态代理概述Code 动态代理概述实现方式一 - JDK代理或接口代理概述Code 实现方式二 - CGLib 子类代理 (Code Generation Library)概述pom依赖Code Pre Java-JDK动态代理 Java-CGLib动态代理 概述 代理模式是一种结构型设计模式&#xff0c;其目的是为其他对…

我们常说这个pycharm里有陷阱,第三方库导入失败,看这里!

最近有小伙伴遇到了明明安装了 python 第三方库&#xff0c;但是在 pycharm 当中却导入不成功的问题。 ​ 一直以来&#xff0c;也有不少初学 python 的小伙伴&#xff0c;一不小心就跳进了虚拟环境和系统环境的【陷阱】中。 本文就基于此问题&#xff0c;来说说在 pycharm 当…

PPT颜色又丑又乱怎么办?

一、设计一套PPT时&#xff0c;可以从这5个方面进行设计 二、PPT颜色 &#xff08;一&#xff09;、PPT常用颜色分类 一个ppt需要主色、辅助色、字体色、背景色即可。 &#xff08;二&#xff09;、搭建PPT色彩系统 设计ppt时&#xff0c;根据如下几个步骤&#xff0c;依次选…

基于vue3+webpack5+qiankun实现微前端

一 主应用改造&#xff08;又称基座改造&#xff09; 1 在主应用中安装qiankun(npm i qiankun -S) 2 在src下新建micro-app.js文件&#xff0c;用于存放所有子应用。 const microApps [// 当匹配到activeRule 的时候&#xff0c;请求获取entry资源&#xff0c;渲染到containe…

threejs点击模型实现模型边缘高亮的选中效果--更改后提高帧率

先来个效果图 之前写的那个稍微有点问题&#xff0c;帧率只有30&#xff0c;参照官方代码修改后&#xff0c;帧率可以达到50了&#xff0c;在不全屏的状态下&#xff0c;帧率60 1.首先需要导入库 // 用于模型边缘高亮 import { EffectComposer } from "three/examples/js…

Leetcode-每日一题【剑指 Offer 25. 合并两个排序的链表】

题目 输入两个递增排序的链表&#xff0c;合并这两个链表并使新链表中的节点仍然是递增排序的。 示例1&#xff1a; 输入&#xff1a;1->2->4, 1->3->4输出&#xff1a;1->1->2->3->4->4 限制&#xff1a; 0 < 链表长度 < 1000 解题思路 1…

http协议详解

HTTP是什么&#xff1f; HTTP 是一种用作获取诸如 HTML 文档这类资源的协议。它是 Web 上进行任何数据交换的基础&#xff0c;同时&#xff0c;也是一种客户端—服务器&#xff08;client-server&#xff09;协议&#xff0c;也就是说&#xff0c;请求是由接受方——通常是浏览…