WebSocket.onmessage需手动JSON.parse(e.data)并加try...catch校验字段,广播时须过滤发送者自身,send前需JSON.stringify对象且检查readyState===1。

WebSocket.onmessage 里没解析 JSON 就直接用 e.data
常见错误是把服务端发来的消息当字符串直接塞进 DOM,结果页面显示 {"fromName":"张三","message":"你好"} 这种原始 JSON 文本。浏览器不会自动解析,必须手动 JSON.parse(e.data)。
使用场景:服务端统一用 JSON 格式推送消息(比如 {"type":"chat","from":"李四","content":"晚安"} 或 {"type":"system","content":"王五已加入"}),前端必须先解析再取字段。
容易踩的坑:
- 没加
try...catch,服务端偶尔发个非 JSON 字符串(比如空值、纯文本错误提示),JSON.parse报错导致整个onmessage失效 - 解析后没校验字段是否存在,直接访问
data.from,遇到格式异常消息就undefined渲染 - 把
e.data当成 DOM 元素传给innerHTML,可能引发 XSS(尤其服务端未过滤用户输入时)
服务端广播时遍历 connections 却漏掉发送者自己
多人聊天室里,“张三发消息”要让“李四、王五、赵六”都收到,但默认不包括张三自己——除非你明确想让他也看到自己刚发的内容(比如带时间戳回显)。很多新手直接 for (const client of connections) client.send(...),结果张三在输入框按一次回车,聊天区刷出两条一模一样的消息。
性能影响:多发一次无意义消息,看似微小,但连接数上万时,带宽和序列化开销会线性增长。
实操建议:
- 服务端记录每个连接对应的用户标识(如
client.userId = 'zhangsan') - 广播前过滤:
connections.filter(c => c.userId !== senderId).forEach(...) - 如果需要“自己也看到”,单独处理:先发给自己,再广播给其他人
websocket.send() 传对象不序列化就报错
浏览器原生 WebSocket.send() 只接受 string 或 ArrayBuffer 类型,传入 JS 对象(如 {to: 'lisi', msg: 'hi'})会直接抛 TypeError: Failed to execute 'send' on 'WebSocket': Data must be a string or ArrayBuffer。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
原因很简单:协议层不认 JS 对象,只认字节流。必须手动转成字符串才能发。
正确做法:
- 发送前一律
websocket.send(JSON.stringify({to: 'lisi', msg: 'hi'})) - 别依赖后端自动反序列化——不同语言/框架对非 JSON 输入容忍度不同,Node.js 的
ws库会静默失败,Spring Boot 则可能直接断连 - 如果消息含二进制(如图片 base64),用
ArrayBuffer更合适,但聊天室文本场景基本用不到
连接关闭后还调用 websocket.send() 导致 Uncaught Error
用户切页、关标签、网络抖动都会触发 onclose,但前端逻辑未必及时清理状态。比如发送按钮没置灰,用户点一下,控制台立刻报 WebSocket is already in CLOSING or CLOSED state。
这不是服务端问题,是前端没管好连接生命周期。
关键判断点:
- 检查
websocket.readyState:0=CONNECTING,1=OPEN,2=CLOSING,3=CLOSED;只有=== 1才能安全发 - 发送前加守卫:
if (ws.readyState === WebSocket.OPEN) { ws.send(...) } - 更稳妥的做法是点击发送时先禁用按钮,
onopen后再启用,onclose时也禁用并提示“连接已断开”
真实项目里,连接状态比想象中脆弱——WiFi 切 4G、锁屏唤醒、Chrome 后台节流都可能导致 readyState 突然变 0 或 3。别假设“连上了就一直在线”。

















