WebSocket连接失败需动态生成URL并用wss协议;后端选@EnableWebSocketMessageBroker支持STOMP实现订阅/广播;前端解析JSON需手动parse;告警逻辑应在服务端用Redis计数器和分布式锁兜底。

WebSocket 连接失败时前端报 Failed to construct 'WebSocket' 怎么办
常见错误是直接写死 "ws://localhost:8080/ws",但实际部署后域名、端口、协议都变了。浏览器会因跨域或协议不匹配直接抛错,连 onerror 都进不去。
正确做法是动态拼接 URL:
- 用
window.location.protocol.replace('http', 'ws')自动转ws://或wss:// - 路径别硬编码,统一走
/ws或后端配置的 endpoint(如/ws-monitor) - 生产环境必须用
wss://,否则 Chrome 会直接拦截未加密的 WebSocket 连接
示例:new WebSocket(`${window.location.protocol.replace('http', 'ws')}//${window.location.host}/ws`)
Spring Boot 后端配 @ServerEndpoint 还是 @EnableWebSocketMessageBroker
二者根本不是一回事,选错会导致消息根本推不出去。
@ServerEndpoint 是原生 JSR-356 实现,适合简单点对点推送(比如单设备告警只发给绑定的护理员),但要自己管理 session、广播逻辑、序列化。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
@EnableWebSocketMessageBroker 是 Spring 封装的 STOMP 协议支持,自带 topic 订阅/发布、权限控制、心跳保活,适合监控大屏这类多客户端订阅同一数据源的场景。
- 告警要推给所有在线运维人员 → 用
SimpleBroker+/topic/alerts - 告警只推给某台设备的负责人 → 用
UserDestinationMessageHandler+/user/{userId}/queue/alerts - 需要断线重连、消息确认、心跳 → STOMP 是刚需,
@ServerEndpoint得自己撸
前端收到 onmessage 但弹窗不触发,检查这三点
最常踩的坑不是代码写错,而是浏览器策略和 DOM 状态干扰。
- 全屏状态下弹窗被拦截:必须先调用
document.exitFullscreen()再show(),否则 Vue/React 组件可能渲染失败 - 音频自动播放被禁止:Chrome 要求用户至少一次交互后才能播声音,告警音效得用
audio.play().catch(e => console.warn("Audio blocked"))容错 - 消息体是字符串但前端当 JSON 解析:后端用
SimpMessagingTemplate.convertAndSend()推的是 JSON 字符串,前端需JSON.parse(evt.data);而@ServerEndpoint默认发纯文本,得自己session.getBasicRemote().sendText(JSON.stringify(...))
告警重复推送、沉默周期失效,后端逻辑怎么兜住
WebSocket 只负责“送达”,不保证“业务语义”。阈值判断、持续周期、沉默周期这些必须在服务端告警检测环节做完,不能依赖前端去 dedupe。
- 持续周期(如“连续3次超温才告警”):用 Redis 的
INCR+EXPIRE维护设备维度计数器,60 秒内累计达 3 次再触发 - 沉默周期(如“5 分钟内不重复推同类型告警”):用
SETNX写入alert:{deviceId}:temp,过期时间设为 300 秒 - 避免并发写入冲突:检测逻辑加分布式锁(如 Redisson),否则高并发下可能漏判或误判
WebSocket 推送只是最后一环,前面的告警判定才是决定准确性的关键。别把业务规则塞进连接层。










