当前位置: 首页 > news >正文

WebSocket详细教程 - SpringBoot实战指南

目录

1. 什么是WebSocket

1.1 基本概念

1.2 形象比喻

1.3 核心特点

2. WebSocket vs HTTP对比

2.1 通信方式对比

2.2 详细对比表

3. WebSocket协议原理

3.1 连接建立过程

步骤1:客户端发起握手请求

步骤2:服务器响应握手

步骤3:协议升级完成

3.2 数据帧格式

4. SpringBoot中的WebSocket

4.1 添加依赖

4.2 SpringBoot中的两种实现方式

5. 基础实现示例

5.1 原生WebSocket实现

5.1.1 WebSocket配置类

5.1.2 WebSocket处理器

5.1.3 前端JavaScript代码

6. STOMP协议详解

6.1 什么是STOMP

6.2 STOMP的优势

6.3 STOMP配置

6.3.1 配置类

6.3.2 消息控制器

6.3.3 消息实体类

6.3.4 WebSocket事件监听器

6.3.5 前端STOMP客户端

7. 完整项目实战

7.1 项目结构

7.2 主要业务逻辑

7.2.1 聊天服务类

7.2.2 增强的聊天控制器

8. 高级特性

8.1 身份验证和授权

8.1.1 WebSocket安全配置

8.2 消息持久化

8.2.1 消息实体

8.2.2 消息仓库

8.3 集群支持

8.3.1 Redis消息代理配置

9. 最佳实践

9.1 连接管理

9.1.1 连接池管理

9.2 错误处理和重连机制

9.2.1 客户端重连逻辑

9.3 性能优化

9.3.1 消息限流

9.3.2 消息压缩

10. 常见问题与解决方案

10.1 连接问题

问题1:WebSocket连接被防火墙阻止

问题2:跨域问题

10.2 性能问题

问题1:内存泄漏

问题2:消息堆积

10.3 安全问题

问题1:未授权访问

问题2:消息内容过滤

🎯 总结

学习建议

适用场景


1. 什么是WebSocket

1.1 基本概念

WebSocket是一种网络通信协议,提供了全双工通信能力。简单来说:

  • 传统HTTP:客户端问一次,服务器答一次(单向请求-响应)
  • WebSocket:客户端和服务器可以随时互相发送消息(双向实时通信)

1.2 形象比喻

想象一下:

  • HTTP就像写信:你写信给朋友,朋友收到后回信给你,一来一回
  • WebSocket就像打电话:连接建立后,双方都可以随时说话,实时交流

1.3 核心特点

特点说明
持久连接一次握手,持续通信
全双工双方都可主动发送消息
低延迟无需重复建立连接
轻量级数据传输开销小

2. WebSocket vs HTTP对比

2.1 通信方式对比

HTTP通信流程:
客户端 ──请求──> 服务器
客户端 <──响应── 服务器
客户端 ──请求──> 服务器  (新的连接)
客户端 <──响应── 服务器WebSocket通信流程:
客户端 ──握手请求──> 服务器
客户端 <──握手响应── 服务器
客户端 <──────────> 服务器  (持续双向通信)

2.2 详细对比表

对比项HTTPWebSocket
连接性质无状态、短连接有状态、长连接
通信方向单向(请求-响应)双向(全双工)
服务器推送不支持原生支持
协议开销每次请求都有完整HTTP头握手后开销极小
实时性差(需要轮询)优秀(即时推送)
适用场景一般Web应用实时应用(聊天、游戏等)

3. WebSocket协议原理

3.1 连接建立过程

步骤1:客户端发起握手请求
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
步骤2:服务器响应握手
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
步骤3:协议升级完成

连接从HTTP协议升级为WebSocket协议,开始全双工通信。

3.2 数据帧格式

WebSocket使用帧(Frame)来传输数据:

 0                   1                   2                   30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +

4. SpringBoot中的WebSocket

4.1 添加依赖

<dependencies><!-- SpringBoot Web Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- SpringBoot WebSocket Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>
</dependencies>

4.2 SpringBoot中的两种实现方式

方式特点适用场景
原生WebSocket底层API,灵活度高简单点对点通信
STOMP协议高级消息协议,功能丰富复杂消息系统

5. 基础实现示例

5.1 原生WebSocket实现

5.1.1 WebSocket配置类
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {// 注册WebSocket处理器registry.addHandler(new MyWebSocketHandler(), "/websocket").setAllowedOrigins("*"); // 允许跨域}
}
5.1.2 WebSocket处理器
@Component
public class MyWebSocketHandler extends TextWebSocketHandler {// 存储所有WebSocket会话private static final Set<WebSocketSession> sessions = Collections.synchronizedSet(new HashSet<>());/*** 连接建立成功调用的方法*/@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {sessions.add(session);System.out.println("连接建立:" + session.getId());// 向新连接的客户端发送欢迎消息session.sendMessage(new TextMessage("欢迎连接WebSocket服务器!"));}/*** 接收到消息时调用的方法*/@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {String payload = message.getPayload();System.out.println("收到消息:" + payload);// 广播消息给所有连接的客户端broadcastMessage("用户说:" + payload);}/*** 连接关闭后调用的方法*/@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {sessions.remove(session);System.out.println("连接关闭:" + session.getId());}/*** 传输错误时调用的方法*/@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {System.out.println("传输错误:" + exception.getMessage());sessions.remove(session);}/*** 广播消息给所有客户端*/private void broadcastMessage(String message) {synchronized (sessions) {for (WebSocketSession session : sessions) {try {if (session.isOpen()) {session.sendMessage(new TextMessage(message));}} catch (Exception e) {e.printStackTrace();}}}}
}
5.1.3 前端JavaScript代码
<!DOCTYPE html>
<html>
<head><title>WebSocket测试</title>
</head>
<body><div><input type="text" id="messageInput" placeholder="输入消息..."><button onclick="sendMessage()">发送</button><button onclick="connect()">连接</button><button onclick="disconnect()">断开</button></div><div id="messages"></div><script>let socket = null;function connect() {socket = new WebSocket('ws://localhost:8080/websocket');socket.onopen = function(event) {console.log('WebSocket连接已建立');addMessage('已连接到服务器');};socket.onmessage = function(event) {console.log('收到消息:', event.data);addMessage('服务器:' + event.data);};socket.onclose = function(event) {console.log('WebSocket连接已关闭');addMessage('连接已断开');};socket.onerror = function(error) {console.log('WebSocket错误:', error);addMessage('连接错误:' + error);};}function sendMessage() {const input = document.getElementById('messageInput');if (socket && socket.readyState === WebSocket.OPEN) {socket.send(input.value);addMessage('我:' + input.value);input.value = '';} else {alert('请先连接WebSocket');}}function disconnect() {if (socket) {socket.close();}}function addMessage(message) {const messages = document.getElementById('messages');cons
http://www.lryc.cn/news/582809.html

相关文章:

  • 华中科大首创DNN衍射量子芯片登《Science Advances》:3D打印实现160μm³高维逻辑门
  • 【零基础学AI】第30讲:生成对抗网络(GAN)实战 - 手写数字生成
  • AI标注平台label-studio之二添加机器学习后端模型辅助标注
  • 【计算机网络】第三章:数据链路层(上)
  • C++ 的 copy and swap 惯用法
  • CompareFace人脸识别算法环境部署
  • Foundry 依赖库管理实战
  • 代码详细注释:ARM-Linux字符设备驱动开发案例:LCD汉字输出改进建议开发板断电重启还能显示汉字,显示汉字位置自定义
  • 常见前端开发问题的解决办法
  • 什么是2.5G交换机?
  • 德隆专家:投资“三知道”原则
  • React Native 一些API详解
  • docker proxy
  • 容器技术入门之Docker环境部署
  • Docker企业级应用:从入门到生产环境最佳实践
  • Docker部署前后端项目完整教程(基于Spring Boot项目)
  • 【计算机组成原理】-CPU章节学习篇—笔记随笔
  • 开疆智能Profinet转DeviceNet网关连接掘场空气流量计配置案例
  • 用 Spring Boot + Redis 实现哔哩哔哩弹幕系统(上篇博客改进版)
  • RHA《Unity兼容AndroidStudio打Apk包》
  • 分享|大数据采集工程师职业技术报考指南
  • C# IIncrementalGenerator干点啥
  • N8N与Dify:自动化与AI的完美搭配
  • 基于Java+Maven+Testng+Selenium+Log4j+Allure+Jenkins搭建一个WebUI自动化框架(1)搭建框架基本雏形
  • UE5内置插件 AnimToTexture 简单入门
  • Spring Boot 项目中的多数据源配置
  • ElasticSearch集群状态查询及_cat 命令详解
  • GitHub Copilot 三种模式详解:Ask、Agent、Edit
  • 【web安全】SQLMap 参数深度解析:--risk 与 --level 详解
  • leetcode-二叉树的层序遍历-113