WebSocket JSON报错主因是数据校验缺失而非协议问题,需明确服务端序列化、客户端守门、分层监控三环节责任。

WebSocket传输JSON数据报错,八成不是协议问题,而是服务端发了非法JSON、客户端没校验就直接JSON.parse(),或者中间代理/日志工具悄悄改了引号。解决重点不在“怎么传”,而在“谁负责校验”和“错在哪一层”。
服务端发JSON前必须用json.Marshal或等效函数序列化
Go里用websocket.JSON.Send(如gorilla/websocket旧版)会自动序列化,但容易掩盖类型错误;新版推荐手动json.Marshal + WriteMessage,好处是能提前捕获结构体字段不可导出、循环引用等问题。
- 避免直接传map或struct字面量,先
data, err := json.Marshal(v),err != nil时立刻记录并返回400错误帧 - 不要依赖
JSON_UNESCAPED_UNICODE这类PHP式选项——Go默认不转义中文,但若结构体字段含nil指针且未设omitempty,可能产出null导致前端解析歧义 - Go服务端示例:
msg := map[string]interface{}{"code": 200, "data": user} body, err := json.Marshal(msg) if err != nil { log.Printf("marshal failed: %v", err) return // 不发送残缺数据 } err = conn.WriteMessage(websocket.TextMessage, body)
客户端收到evt.data后不能直接JSON.parse()
WebSocket帧内容可能是string或ArrayBuffer,且服务端若发了非JSON字符串(如纯文本、HTML片段、带前缀的日志标记),JSON.parse()必报Unexpected token。必须加一层格式守门员。
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
- 先检查
typeof evt.data === 'string'且evt.data.trim().startsWith('{')或[,否则丢弃并上报Message Parse Error - 禁止用
replace(/'/g, '"')这种野路子修复单引号——JSON标准只认双引号,单引号说明服务端根本没走JSON序列化流程,该修后端而不是前端 - 简单守门示例:
ws.onmessage = function(evt) { const raw = typeof evt.data === 'string' ? evt.data.trim() : ''; if (!raw || (!raw.startsWith('{') && !raw.startsWith('['))) { console.warn('Invalid JSON frame:', raw); reportToMonitoring({ type: 'bad_message', raw }); return; } try { const obj = JSON.parse(raw); handleMsg(obj); } catch (e) { console.error('JSON parse failed:', e, raw); reportToMonitoring({ type: 'parse_error', raw, error: e.message }); } };
监控要区分1006、4000+和parse error三类错误
连接断开码1006代表底层链路死亡,而4000+是服务端主动抛的业务错误,parse error则纯属数据格式失格——三者修复路径完全不同,混在一起监控等于无效。
-
1006:查Nginx是否漏配Upgrade头、客户端网络是否切换、服务端是否OOM被杀 -
4000+:看服务端日志里对应错误码的reason字段,比如4001可能是token过期,需前端跳登录页 -
parse error:在客户端catch块里上报原始evt.data,服务端收到后立刻检查json.Marshal调用点是否被绕过 - 关键埋点字段必须包含:
url、event.code(关闭码)、event.reason、raw_data(仅parse error时)、timestamp
真正难的不是写重连逻辑或心跳包,而是当JSON.parse()报错时,你能一眼从监控里定位到是哪个服务端节点、哪行WriteMessage调用绕过了json.Marshal——这要求所有发送路径统一收口,且每条错误日志带足够上下文。

















