1. 引言
HTTP(超文本传输协议)是一种无状态的请求-响应协议。其简单设计使其具备良好的可扩展性,但对于高度交互的实时Web应用来说却存在明显缺陷——每个请求/响应都需要传输大量开销数据,导致效率低下。
由于HTTP是同步协议,而实时应用需要异步通信,轮询或长轮询(如Comet技术)等解决方案往往复杂且低效。
为解决上述问题,我们需要一个基于标准的双向全双工协议,能同时被服务器和客户端使用。JSR 356 API应运而生——本文将展示其实际应用示例。
2. 环境配置
在项目中添加Spring WebSocket依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>6.0.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>6.0.13</version>
</dependency>
⚠️ 始终从Maven中央仓库获取最新版本:
3. STOMP协议
STOMP(流文本定向消息协议)是一种简单、可互操作的线格式协议,允许客户端与几乎所有消息代理通信。它是AMQP(高级消息队列协议)和JMS(Java消息服务)的替代方案。
STOMP定义了客户端/服务器使用消息语义进行通信的协议,这些语义构建在WebSocket之上,定义了映射到WebSocket帧的帧格式。
使用STOMP可以灵活地用不同编程语言开发客户端和服务器。本示例将使用STOMP实现客户端与服务器间的消息传递。
4. WebSocket服务器
关于WebSocket服务器的构建细节,可参考这篇文章。
5. WebSocket客户端
要与WebSocket服务器通信,客户端需通过发送HTTP请求发起连接,请求中需正确设置Upgrade
头部:
GET ws://websocket.example.com/ HTTP/1.1
Origin: http://example.com
Connection: Upgrade
Host: websocket.example.com
Upgrade: websocket
✅ 注意:
- WebSocket URL使用
ws
和wss
协议(后者表示安全WebSocket) - 服务器若支持WebSocket,会在响应中返回
Upgrade
头部:
HTTP/1.1 101 WebSocket Protocol Handshake
Date: Wed, 16 Oct 2013 10:07:34 GMT
Connection: Upgrade
Upgrade: WebSocket
完成此过程(即WebSocket握手)后,初始HTTP连接被同一TCP/IP连接上的WebSocket连接取代,此后双方即可自由交换数据。
客户端连接通过WebSocketStompClient
实例发起。
5.1 WebSocketStompClient详解
如第3节所述,首先需建立WebSocket连接,这通过WebSocketClient
类实现。WebSocketClient
可通过以下方式配置:
- JSR-356实现(如Tyrus)提供的
StandardWebSocketClient
- Jetty 9+原生WebSocket API提供的
JettyWebSocketClient
- Spring的任何
WebSocketClient
实现
本示例使用StandardWebSocketClient
:
WebSocketClient client = new StandardWebSocketClient();
WebSocketStompClient stompClient = new WebSocketStompClient(client);
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
StompSessionHandler sessionHandler = new MyStompSessionHandler();
stompClient.connect(URL, sessionHandler);
new Scanner(System.in).nextLine(); // 防止程序立即退出
❌ 踩坑提醒:
- 默认情况下
WebSocketStompClient
使用SimpleMessageConverter
- 处理JSON消息时,必须设置为
MappingJackson2MessageConverter
才能实现JSON与对象的转换
连接接口时需传入StompSessionHandler
实例,用于处理afterConnected
和handleFrame
等事件。
若服务器支持SockJS,可将客户端改为使用SockJsClient
替代StandardWebSocketClient
。
5.2 StompSessionHandler实现
使用StompSession
订阅WebSocket主题需创建StompSessionHandlerAdapter
实例(实现StompSessionHandler
接口)。
StompSessionHandler
提供STOMP会话的生命周期事件:
- 会话建立时的回调
- 失败时的通知机制
当WebSocket客户端连接到接口后,StompSessionHandler
会收到通知并调用afterConnected()
方法,在此方法中通过StompSession
订阅主题:
@Override
public void afterConnected(
StompSession session, StompHeaders connectedHeaders) {
session.subscribe("/topic/messages", this);
session.send("/app/chat", getSampleMessage());
}
@Override
public void handleFrame(StompHeaders headers, Object payload) {
Message msg = (Message) payload;
logger.info("Received : " + msg.getText()+ " from : " + msg.getFrom());
}
✅ 运行效果: 确保WebSocket服务器运行后启动客户端,控制台将输出:
INFO o.b.w.client.MyStompSessionHandler - New session established : 53b993eb-7ad6-4470-dd80-c4cfdab7f2ba
INFO o.b.w.client.MyStompSessionHandler - Subscribed to /topic/messages
INFO o.b.w.client.MyStompSessionHandler - Message sent to websocket server
INFO o.b.w.client.MyStompSessionHandler - Received : Howdy!! from : Nicky
6. 总结
本教程简单粗暴地实现了基于Spring的WebSocket客户端。完整代码可在GitHub仓库获取。