必须显式调用JSON.stringify()将对象转为字符串,否则send()发送的是"[object Object]";收发两端均需手动序列化与反序列化,且须加try-catch处理循环引用、undefined等异常。

WebSocket 本身不认 JSON,只收字符串或二进制数据;传对象不 stringify 就等于发 "[object Object]",服务端根本收不到有效结构。
前端发送前必须 JSON.stringify()
原生 WebSocket.send() 只接受 string、ArrayBuffer、Blob 或 TypedArray。直接传 JS 对象(如 {type: "login", user: "Alice"})不会报语法错误,但实际发出的是 String({}) —— 即 "[object Object]"。
- 必须显式调用
JSON.stringify(message),这是不可省略的一步 - 建议包裹
try...catch:循环引用、undefined、Date实例、函数字段都会导致JSON.stringify()抛TypeError,进而静默丢包 -
Date.now()安全,但new Date()不行;Map/Set需手动转为普通对象再序列化 - 示例写法:
const msg = { type: "ping", timestamp: Date.now(), payload: "ok" };
try {
socket.send(JSON.stringify(msg));
} catch (e) {
console.error("JSON stringify failed:", e);
}
后端接收后必须 json.loads() 或 JSON.parse()
无论 Python(Django/Flask)、Java(Spring Boot)、Node.js 还是 Go,WebSocket 收到的都是原始字节流或字符串,框架不会自动解析成对象。
- Django +
channels:收到的text_data是字符串,需手动json.loads(text_data) - Spring Boot +
@OnMessage:参数若为String,也得自己new ObjectMapper().readValue(payload, MyDto.class) - Node.js +
ws库:回调中data是string或Buffer,typeof data === "string"时才可JSON.parse(data) - 务必加异常处理:非法 JSON(如多逗号、单引号、BOM 字符 \ufeff)会导致解析失败,不捕获就崩
常见错误现象和排查点
这些表现基本都能定位到序列化/反序列化环节没做对:
- 前端控制台没报错,但服务端日志里收到的是
"[object Object]"或空字符串 → 忘了JSON.stringify() - 服务端解析时报
JSONDecodeError/SyntaxError: Unexpected token→ 前端发了非法 JSON(比如字段值含未转义换行符),或消息被截断、粘包 - 小程序里
JSON.parse()失败但字符串看着“明明是对的” → 检查是否有隐藏 BOM(\ufeff)或零宽空格,先str.replace(/\ufeff/g, "") - Go 或 Java 后端收到数据是乱码(中文变问号)→ WebSocket 文本帧默认 UTF-8,但若前端用了非标准编码生成字符串(极少见),或中间代理篡改了 Content-Type(虽然 WebSocket 不走 HTTP header,但某些网关会干预)
要不要加 Content-Type: application/json?
WebSocket 协议层没有 header 概念,send() 发出的纯文本帧不携带 MIME 类型。所谓“加 Content-Type”只在两种场景有意义:
- 你在 WebSocket 上模拟 HTTP 行为(比如封装成带 header 的自定义协议),那属于业务约定,需两端一致实现
- 用 WebSocket 代理或调试工具(如 Wireshark、Chrome DevTools 的 Network → WS Frames)查看时,工具可能根据 payload 猜测类型,但不影响传输本身
- 真正需要关注的是:前后端对字段名、嵌套层级、空值处理(
nullvsundefined)、时间戳格式(毫秒数 vs ISO 字符串)是否达成一致——这些比“标不标 JSON”重要得多
最易被忽略的一点:WebSocket 连接建立后,第一次发消息前,别假设对方“已经 ready”。有些服务端在 @OnOpen 回调里还没完成 session 初始化,立刻 send() 可能被丢弃。加个简单心跳或延时 100ms 再发首条 JSON,比反复调试序列化逻辑更省时间。


















