websocket onmessage未触发,首要确认连接是否真正建立(readystate===1),常见原因是onmessage在连接就绪前绑定、被重复赋值覆盖、服务端未实际推送或消息类型不匹配。

WebSocket onmessage 回调没触发?先确认连接已建立
服务端推送的数据收不到,90% 的情况不是 onmessage 写错了,而是连接压根没成功。WebSocket 是全双工长连接,必须等 readyState === 1 才能收发数据。
常见错误现象:onmessage 函数已定义,但服务端发了消息,浏览器控制台完全没反应,console.log 也不执行。
- 务必在
onopen回调里再绑定onmessage,或至少用if (ws.readyState === WebSocket.OPEN)做双重保险 - 不要在
new WebSocket(...)后立刻写ws.onmessage = ...就以为万事大吉——构造函数是异步的,此时readyState很可能还是0(CONNECTING) - 检查浏览器开发者工具 Network 面板,过滤
ws或websocket,看连接状态是否为 “Active”,有没有 400/401 错误或被拦截
服务端推送的是字符串还是 ArrayBuffer?onmessage.data 类型决定解析方式
onmessage 回调收到的 data 不一定是字符串。服务端调用 send() 时传入什么类型,客户端就收到什么类型——这直接影响你能否直接 JSON.parse()。
常见错误现象:服务端发了 { "type": "update", "value": 123 },但前端 JSON.parse(event.data) 报错 Unexpected token 或 Unexpected end of JSON input。
- 如果服务端发的是
Buffer、Uint8Array或二进制帧,event.data会是ArrayBuffer或Blob,需手动转字符串:new TextDecoder().decode(event.data) - 如果服务端明确发的是文本帧(如 Node.js 的
ws.send(JSON.stringify(obj))),event.data才是string,可直接JSON.parse() - 可在回调开头加
console.log(typeof event.data, event.data)快速确认类型,避免盲目解析
多个 onmessage 赋值覆盖?事件监听器别重复绑定
在 SPA 或组件反复挂载/卸载场景下,很容易无意中多次执行 ws.onmessage = function() {...},导致只有最后一次赋值生效,前面的逻辑全部丢失。
常见错误现象:页面切换几次后,实时数据突然“断连”或只处理部分消息,重启页面又正常。
- 避免在组件
mounted/useEffect里无条件重写ws.onmessage;改用ws.addEventListener('message', handler)并保存引用,便于后续removeEventListener - 如果坚持用赋值方式,确保每次新建连接前先清理旧连接:
oldWs?.onmessage = null,否则旧连接残留的 handler 可能还在内存里 - 注意:WebSocket 对象不可复用,
close()后再new一个新实例,旧实例上的所有事件监听器自动失效,但若变量未置空,仍可能引发意外交互
数据粘包或分片?onmessage 每次只收一帧,但服务端可能拆包
WebSocket 协议本身不保证“一次 send() 对应一次 onmessage”。服务端高并发推送或大 payload 时,可能被底层 TCP 分片,浏览器仍会按帧完整触发 onmessage;但若服务端主动分多帧发送(比如用 send(data, { binary: true, fin: false })),你就得自己拼接。
常见错误现象:收到的消息是半截 JSON,JSON.parse() 报错;或者日志显示连续两次 onmessage,但第二次 data 是空或不完整对象。
- 绝大多数 Web 场景(如
ws库、Socket.IO 封装层)默认发完整文本帧,无需手动拼接;只有你显式使用流式发送或自研协议时才需处理分片 - 判断是否分片:检查
event.data类型是否为ArrayBuffer,且event.isTrusted === false(非标准字段,仅作参考),更可靠的方式是和服务端约定消息边界,例如每条消息以\n结尾,或前置 4 字节长度头 - 简单防御:在
onmessage里加try/catch包裹JSON.parse(),失败时缓存data并等待下次,但前提是服务端支持重传或你有重试机制
真正容易被忽略的点:服务端写的“实时推送”未必真推到了浏览器——它可能卡在代理(如 Nginx 默认 60s 断连)、CDN 缓存、或 TLS 握手后的 idle timeout。别急着改前端,先用 wscat -c ws://your-domain.com 直连服务端,确认消息确实发出来了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











