STOMP在Spring Boot中需端点注册、消息代理配置、客户端订阅三者缺一不可:addEndpoint()路径须与前端连接URL完全一致;enableSimpleBroker()声明的前缀决定消息路由;客户端必须在onConnect后显式subscribe对应路径,否则消息静默丢失。

STOMP在Spring Boot里不是“配好就能用”的协议,它依赖三个不可缺位的环节:端点注册、消息代理配置、客户端订阅动作。少一个,消息就发不出去或收不到。
registerStompEndpoints() 里 addEndpoint() 必须匹配前端连接URL
常见错误是后端写了 addEndpoint("/ws"),前端却连 ws://localhost:8080/stomp 或漏掉路径前缀。连接失败时浏览器控制台通常报 WebSocket connection to '...' failed,但实际原因常被误判为CORS或服务未启动。
- 端点路径必须完全一致,包括斜杠:后端
addEndpoint("/ws")→ 前端 new StompClient("ws://host:port/ws") -
setAllowedOrigins()在开发阶段不能只写"*";Spring Boot 2.4+ 默认拒绝通配符,需显式列出如"http://localhost:3000" - 不用
withSockJS()时,确保浏览器支持原生 WebSocket(IE10+、所有现代浏览器都行);用了则前端必须引入 sockjs-client + stomp.js
configureMessageBroker() 中 enableSimpleBroker() 决定消息能否被路由
这个方法声明了哪些前缀的消息会被 Spring 的内存代理接收并广播。如果客户端往 /topic/notice 发送消息,但配置里没包含 "/topic",消息直接被丢弃,无日志、无报错、无声无息。
- 广播场景(所有人收到):用
enableSimpleBroker("/topic"),配合@SendTo("/topic/xxx")或SimpMessagingTemplate.convertAndSend("/topic/xxx", ...) - 点对点场景(仅指定用户):必须加
"/user",且前端订阅路径要带/user/queue/xxx,服务端推送要用@SendToUser或convertAndSendToUser - 多个前缀可同时启用:
enableSimpleBroker("/topic", "/user", "/queue"),但每个都要有对应用途,别堆砌
客户端不 SUBSCRIBE,服务端发再多 SEND 也没用
这是最常被忽略的一环。STOMP 是发布-订阅模型,不是“服务器喊话,客户端自动听”。服务端调用 @SendTo("/topic/chat") 只是把消息扔进代理,真正决定谁收到的,是客户端是否执行了 client.subscribe("/topic/chat", ...)。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 订阅必须在 WebSocket 连接成功(
onConnect回调内)之后进行,不能在连接前或连接失败时尝试 - 订阅路径必须与
enableSimpleBroker()中声明的前缀一致;比如代理启用了"/topic",就不能订阅/app/chat(那是应用前缀,归@MessageMapping处理) - 前端 stomp.js 订阅时若没传回调函数,或回调里没处理
frame.body,看起来就像“收不到消息”——其实收到了,只是没解包打印
Spring Security 拦截 WebSocket 握手请求导致连接 403
WebSocket 连接的第一步是 HTTP Upgrade 请求,Spring Security 默认会拦住它,返回 403 Forbidden。此时浏览器控制台显示 Failed to connect to ws://...,但网络面板里看不到请求,因为被过滤器链在早期就拒了。
- 必须用
WebSecurity.ignoring().antMatchers("/ws/**"),而不是在HttpSecurity里放行;后者仍走认证流程,无效 - 忽略路径要覆盖完整握手路径:如果端点是
/ws,就忽略/ws和/ws/**;如果用了 SockJS,还要加/ws/info等内部路径 - 生产环境严禁用
"*",应精确到前端部署域名,如"https://myapp.com"
STOMP 的难点不在配置语法,而在于理解它的三层职责分离:传输层(WebSocket)、协议层(STOMP帧)、路由层(Broker前缀 + 订阅动作)。任意一层断开,整条链就静默失效——没有错误提示,只有空等。










