WebSocket 实时推送怎么设计:连接、心跳、鉴权和消息边界

3次阅读
没有评论

WebSocket 常被简单理解成“后端主动推消息给前端”。真正落地时,要处理的不是 send 一行代码,而是连接生命周期、心跳、鉴权、断线重连、消息格式、广播范围和多实例部署。

WebSocket 适合什么场景

WebSocket 适合服务端需要持续向客户端推送消息的场景:

  • 聊天消息。
  • 订单状态变化。
  • 实时大屏。
  • 任务进度。
  • 告警通知。
  • 在线协作。

如果只是偶尔刷新状态,轮询或 SSE 可能更简单。WebSocket 适合双向通信和高频推送,但也会带来连接管理成本。

连接不是登录

WebSocket 握手通常从 HTTP 升级而来。连接建立时要做鉴权,但不要把“连接存在”当作“用户永远在线”。

常见做法:

  • 握手时带 token。
  • 服务端校验 token 并绑定 userId。
  • 连接上下文只保存必要身份信息。
  • token 过期或权限变化时主动断开或要求重连。

不要在 URL 里长期暴露敏感 token。如果必须放 query,要确保 HTTPS,并控制 token 有效期。

心跳是必须的

真实网络里,客户端关页、手机休眠、代理断开、Nginx 超时,都可能导致连接半开。服务端不做心跳,就会以为连接还活着。

常见策略:

  • 客户端定期 ping。
  • 服务端定期 pong 或记录最后活跃时间。
  • 超过阈值关闭连接。
  • 客户端指数退避重连。

心跳间隔不要太短,否则本身就会制造流量;也不要太长,否则断线发现太慢。内部系统可以从 20 到 60 秒范围试起,再结合代理超时配置调整。

消息格式要有类型

不要直接推一段裸字符串。建议统一消息结构:

{
  "type": "task.progress",
  "requestId": "abc",
  "timestamp": 1780000000000,
  "payload": {
    "percent": 80
  }
}

至少要有:

  • type:消息类型。
  • payload:业务内容。
  • timestamp:服务端时间。
  • requestIdmessageId:方便排查和去重。

这样前端可以按类型分发,后端日志也能追踪一条消息。

单实例和多实例差别很大

单实例里,连接保存在本机内存 Map 中就能推送:

userId -> sessions

多实例部署后,用户连接可能在任意节点上。A 节点收到业务事件,但用户连接在 B 节点,就需要消息总线:

  • Redis Pub/Sub。
  • MQ。
  • 专门的推送服务。
  • 网关层粘性会话。

小系统可以先单实例跑通,但设计消息接口时要给多实例留边界,不要把所有业务逻辑写死在某个 Controller 的静态 Map 里。

推送失败怎么处理

WebSocket 不是可靠消息队列。连接断了,消息可能发不出去。业务上要区分:

  • 弱实时通知:丢了可以下次刷新看到。
  • 强一致消息:必须落库、确认、补偿。

订单状态、任务结果这类关键状态,应该以数据库为准,WebSocket 只是提示用户刷新或更新 UI。聊天消息、审批通知等需要可靠性时,要有消息 ID、已读/确认和离线补偿。

最后抓住一句话

WebSocket 的核心不是“能推送”,而是把连接、身份、心跳、消息格式和多实例路由设计清楚。关键业务状态仍以数据库或消息系统为准,WebSocket 负责实时体验,不要让它单独承担可靠存储。

正文完
 0
bdspAdmin
版权声明:本站原创文章,由 bdspAdmin 于2026-07-01发表,共计1261字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)