登录
首页 >  文章 >  前端

WebSocket从入门到精通:消息传输全攻略

时间:2026-05-28 16:44:27 242浏览 收藏

WebSocket远不止是“建立连接就完事”的简单协议,其真正的复杂性深藏于消息传输的每个细节之中:从二进制与文本帧的类型匹配、`binaryType` 的显式配置,到 Spring 中 `@OnMessage` 参数类型的严格解析规则;从 `@OnClose` 时 Session 已失效的规范限制,到浏览器异常关闭导致回调丢失的容错设计;再到生产环境中必须禁用的不安全默认项——如通配符跨域、无上限消息尺寸、内存型消息代理,以及极易被忽视却至关重要的业务层心跳机制。这篇文章直击开发者在真实项目中反复踩坑的核心链路,把那些藏在 `onMessage` 回调背后、日志里找不到堆栈、上线后才爆发的隐性陷阱,一次性讲透、理清、给出可落地的解决方案。

WebSocket入门到精通教程 消息接收传输完整知识图谱【汇总】

WebSocket 不是“学会了就能用”,而是“用的时候才发现漏了关键链路”。真正卡住开发者的,从来不是连接建立,而是消息收发过程中那些隐性依赖:会话状态管理、异常重连边界、二进制/文本帧混用、心跳缺失导致的静默断连——这些在 onMessage 回调里根本看不出来。

WebSocket.onMessage 只接收字符串?那二进制数据怎么办

默认情况下,onMessage 回调收到的 event.data 类型取决于服务端发送的内容。如果后端发的是 String,前端拿到的就是字符串;如果发的是 byte[]Blob,前端拿到的就是 BlobArrayBuffer,不会自动转成字符串。

  • 不显式设置 ws.binaryType = 'arraybuffer',收到二进制时可能触发 TypeError: Failed to execute 'atob' on 'Window'(尤其在 base64 解码逻辑里)
  • 服务端用 Spring WebSocket 发送 TextMessage,前端一定收到 string;发 BinaryMessage,前端必须提前设 binaryType 才能安全读取
  • 混合场景建议统一约定:文本走 string,图片/音频/协议包走 ArrayBuffer,并在首字节或前 4 字节嵌入类型标识

Spring Boot 中 @OnMessage 方法参数类型决定消息解析方式

Spring 的 @OnMessage 不是只认 String。它根据方法签名自动匹配并反序列化,但规则很具体:

  • 参数为 String → 自动 UTF-8 解码,抛 DecodeException 若非法字节
  • 参数为 byte[] → 原始字节透传,不解析,适合自定义协议
  • 参数为自定义类(如 ChatMessage)→ 需注册 Decoder.Text,否则直接报 400
  • 没写 @OnError 且解码失败,连接会静默关闭,日志只打印 Failed to decode message,无堆栈

为什么 onclose 触发时 session 已经不可用

@OnClose 方法执行时,Session 对象已处于关闭状态,调用 session.getBasicRemote().sendText() 会抛 IllegalStateException: The session is closed。这不是 bug,是 JSR-356 规范明确要求的行为。

  • 想在断开前发最后一条消息,必须在 @OnMessage 或业务逻辑中预判断连(比如收到 {"type":"logout"})并主动发送
  • 清理资源(如从 ConcurrentHashMap 移除 session)必须放在 @OnClose 里,但不能依赖 session 本身做 I/O
  • 浏览器刷新或关页时,@OnClose 可能不触发(TCP FIN 未送达),所以服务端要配超时踢出 + 心跳检测

生产环境必须关掉的三个默认行为

Spring Boot 内置的 WebSocket 配置在开发时够用,上线后不调整会埋雷:

  • 禁用默认的 SimpleBroker:它用内存 Map 存订阅关系,集群下失效,必须换 RedisMessageBrokerActiveMQ
  • 关闭 setAllowedOrigins("*"):CORS 允许任意源会引发跨站攻击,应精确配置如 ["https://app.example.com"]
  • 限制 maxTextMessageSizemaxBinaryMessageSize:默认不限,大文件上传可能 OOM;建议设为 1024 * 1024(1MB)并配合前端分片

最常被忽略的是心跳帧的处理粒度:Ping/Pong 是 TCP 层保活,但业务层需要独立的心跳消息(如每 30s 交互 {"type":"ping"}),否则 NAT 网关可能在 60s 后单向切断连接,客户端毫无感知。

好了,本文到此结束,带大家了解了《WebSocket从入门到精通:消息传输全攻略》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多文章知识!

资料下载
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>