websocket发送对象前必须json.stringify(),否则服务端收到"[object object]"或空字符串;send仅支持string、arraybuffer等类型;后端需手动json.parse();需防范undefined、function、循环引用导致的序列化失败。

WebSocket 不能直接 send({}),必须先 JSON.stringify(),否则服务端收到的是 "[object Object]" 或空字符串——这是 90% 的新手第一坑。
前端 send() 前不 stringify 就等于发了个空消息
原生 WebSocket.send() 只接受 string、ArrayBuffer、Blob 或 TypedArray。传入 JS 对象(比如 {type: "msg", content: "hello"})不会报语法错误,但实际调用的是 String({}),结果恒为 "[object Object]"。
- 服务端用
JSON.parse()解析时直接抛SyntaxError: Unexpected token o - 某些后端框架(如 Spring WebSocket)会静默丢弃非法 JSON,导致“发了却没收到”
- 即使后端不校验,你也拿不到原始字段——因为根本不是 JSON 字符串
正确写法必须显式序列化:
const socket = new WebSocket("ws://localhost:8080/chat");
socket.onopen = () => {
const msg = { type: "login", user: "Alice", timestamp: Date.now() };
try {
socket.send(JSON.stringify(msg)); // ✅ 关键一步
} catch (e) {
console.error("序列化失败:", e); // 防循环引用、undefined、function 等
}
};
后端接收时必须手动 JSON.parse()
WebSocket 协议层不关心内容格式,它只管收发字节流。服务端拿到的永远是原始 String(或 byte[]),不会自动解析成对象。
- Spring Boot +
@OnMessage:参数类型用String,再手动new ObjectMapper().readValue(payload, Xxx.class) - Node.js +
ws库:回调中data是string或Buffer,需JSON.parse(data.toString()) - Go +
gorilla/websocket:用c.ReadMessage()得到[]byte,再json.Unmarshal()
漏掉这步,你就只能在日志里看到一串原始字符串,没法取 msg.type。
哪些值 JSON.stringify() 会出错?怎么防
JSON.stringify() 对非法值(如 undefined、function、Symbol、循环引用)会静默忽略字段或直接抛错,导致 send 失败且无提示。
-
new Date()→ 转成字符串(安全),但Date.now()更推荐(返回 number) -
undefined字段会被整个删掉;function字段也会被删,不报错但逻辑丢失 - 含循环引用的对象(如
obj.parent = obj)会抛TypeError: Converting circular structure to JSON
简单防御方式:
function safeStringify(obj) {
try {
return JSON.stringify(obj);
} catch (e) {
console.warn("JSON.stringify failed:", e.message);
return JSON.stringify({
error: "invalid payload",
timestamp: Date.now()
});
}
}
要不要封装一个 sendJson() 工具函数
可以,但注意两点:一是别掩盖错误(比如吞掉 catch 不上报),二是别加“自动重试”“自动补字段”这类隐式逻辑——WebSocket 连接状态、重连策略、业务字段校验都该由上层控制。
- 适合封装:统一加
try/catch、打日志、过滤敏感字段(如token) - 不适合封装:自动重连、自动添加
seq或timestamp(除非全项目强约定) - 更推荐方式:用 class 包一层
WebSocketClient,暴露sendJson(msg)方法,内部可控可测
真正容易被忽略的点是:前后端 JSON 格式约定一旦松动(比如某次忘了加 type 字段),错误往往出现在业务逻辑层而非网络层——查起来要翻好几层日志。











