WebSocket 这玩意儿吧,说简单也简单,说复杂也能复杂死你。刚入行那会儿我一直以为它就是个“浏览器能持久连服务端的通信协议”,后来项目做多了,才发现——哦,原来背后是个坑连坑的连环大陷阱
这次我来聊聊我踩过的 WebSocket 六种集成方式,说实话,大部分人可能一辈子都用不到那么多,但你遇上个奇葩需求,或者非要搞集群通信,那这些方式你就得一个个过。
先说点干货(各位产品经理看过来):我推荐的排序顺序其实就和 Spring Boot 的兼容性成正比——Javax、WebMVC、WebFlux 三个能和 Spring 玩得转的,我给它们画个重点 。剩下 Java-WebSocket、SocketIO 和 Netty,我给它们分组叫“搞事情专用”,你如果喜欢造轮子、搞底层优化、或者需求野得一批,欢迎深入。
Javax WebSocket,JSR-356 标准实现,这个方案你一眼就能认出来——@ServerEndpoint、@OnOpen、@OnMessage、@OnClose,全家福注解到齐。而且这是少有的“标准库”,可以不用 Spring,也能跑(当然你真要脱离 Spring,很多时候不是跑不跑得动的问题,是你心理扛不扛得住)...
项目里我用过一段时间 javax 实现,服务端配ServerEndpointExporter,前端只要能连上 ws:// 就能开始收发。唯一让我不爽的是这个注解方式实在太硬核了,配合 Spring 注入有点别扭,每次想注个 Service 还得用SpringContextHolder.getBean(...)这种老土方式,优雅度直接下降 3 个档次。
还有一点细节,JSR 的 ping/pong 是浏览器自动处理的,这一点不错。但是你要搞心跳检查?要么前端定时发心跳消息,要么服务端写个定时扫描活跃连接,反正就是不太优雅。
下面说说 WebMVC 的 WebSocket 集成,也就是 Spring 官方给你的一整套——WebSocketHandler、WebSocketConfigurer、HandshakeInterceptor,一套搞定。
我最喜欢它的一点是“可以写配置类”,就是那种你用 Spring Boot 写惯了的那种配置方式,没有一堆注解散落一地,整洁。比如服务端写个 handler:
public class MyWebSocketHandler implements WebSocketHandler {
public void handleTextMessage(WebSocketSession session, TextMessage message) {
// 逻辑都在这里处理
}
}
然后注册就一句话:
registry.addHandler(new MyWebSocketHandler(), "/ws").addInterceptors(new MyInterceptor());
更骚的玩法还有自定义路径匹配逻辑,那个UrlPathHelper.setRemoveSemicolonContent(false)曾经救过我一次,动态路径支持的效果拉满 。
客户端这块用StandardWebSocketClient配WebSocketConnectionManager,标准但略显繁琐。不过说实话,一旦你配置起来,后面接入多个服务都不是问题,特别适合那些需要服务内服务通信、后台通知这些场景。
至于 WebFlux 的响应式 WebSocket,坦白讲,这个我第一次接触时一脸懵逼:为啥连个消息都要用 Flux?后来项目用了 Netty,我才慢慢爱上这个范儿。
服务端接口:
public class MyReactiveHandler implements WebSocketHandler {
public Mono<Void> handle(WebSocketSession session) {
return session.send(
session.receive()
.doOnNext(msg -> System.out.println("收到:" + msg.getPayloadAsText()))
.map(msg -> session.textMessage("收到啦:" + msg.getPayloadAsText()))
);
}
}
这句代码看着简洁,但你真想写个带状态管理的逻辑,就知道痛苦了。FluxSink 写起来很绕,特别是想加个延时发送、限流、统计这些逻辑,基本全靠自己画地为牢,框架帮不了你多少。
客户端用ReactorNettyWebSocketClient,连接方式是异步的、链式风格的。优点是性能高、负载轻,缺点是...调试起来血压飙升 🧠。
讲真,如果你用的是 WebFlux 做后端,那 WebSocket 就别用 MVC 的那一套了,不然你两个世界的东西混一起,绝对翻车。我们组就有个小哥在 Gateway 那边用了 WebFlux,结果试图接入 MVC 的 WebSocket,调了两天都没通...最终选择重写 🤦。
说完这三种 Spring 系的主力方案,再来看看外围势力:
Java-WebSocket 这个库,我打心底喜欢它的轻量。不依赖 Servlet,不依赖 Spring,直接WebSocketServernew 一个就能跑:
public class MyServer extends WebSocketServer {
public void onMessage(WebSocket conn, String message) {
conn.send("收到你发的:" + message);
}
}
适合写那种临时工具、调试服务、或者一些命令式的业务模块,比如我搞过一个调试 Redis 的在线工具,用 Java-WebSocket + Swing 写的,10分钟起飞。
Socket.IO 就是另一个方向的东西了,它不仅搞 WebSocket,还加了自己的协议封装。断线重连、命名空间、广播机制,都是自带的。你想都不用想,这就是搞 IM、聊天室、多人协作平台的好帮手。
但说实话,Java 这边的 Socket.IO 实现远远没 Node.js 那边香,我当时接手一个项目就是前端 Node 后端 Java,用 socket.io-client 直连 Java 服务,光是 handshake 就卡了我一天...得调版本、搞兼容,最后还是靠抓包和 Fiddler 才找出问题。
Netty 最后说,说白了就是“老子不靠你们任何框架,我自己就是框架”。你想怎么搞就怎么搞,协议你自己设计、握手你自己搞,连消息格式都随便你定义。这玩意我只在高并发场景下用过,比如我们那个实时日志推送系统,就得用 Netty + protobuf,压缩率+吞吐量双赢。
不过 Netty 不建议你手滑就上,一定要评估你是不是能驾驭得住这个家伙。就像开跑车一样,帅是帅,撞一次代价可大 。
最后总结点我自己项目里的感受:
想快速搭项目、跟前端打通,Spring WebMVC 是首选,稳;
如果你项目已经是全 reactive 架构,那就 WebFlux,一体化舒服;
想写跨平台、跨语言的调试工具,可以用 Java-WebSocket;
聊天室、多人互动类业务,Socket.IO 大杀器;
想极限性能、底层定制、或者挑战人生...Netty,欢迎上车!
客户端这块,不管哪种方式,最容易出问题的其实就是“文档太少 + 异常提示烂”,特别是连接失败那种,一堆 UNKNOWN_REASON,调起来跟盲盒一样...
要我说,WebSocket 这个东西,表面看是个简单协议,背后隐藏着无数“到底谁主动断了连接”“为什么发不出去”“为啥掉线了还没重连”的灵异事件。
你们项目里 WebSocket 用的是哪种方式?踩过什么坑?欢迎来评论区交流下
最后,我为大家打造了一份deepseek的入门到精通教程,完全免费:https://www.songshuhezi.com/deepseek
领取专属 10元无门槛券
私享最新 技术干货