为什么 WebSocket 收到的是 object,但 length 却像字符串?
·
一、遇到的问题
1. 使用的环境
- Node.js
- ws (Websocket)
- Postman (用于模拟WebSocket客户端)
2. 问题描述
- 我在本地使用 Node.js 创建了一个 WebSocket 长连接服务,并使用 Postman 作为客户端进行测试。
- 在 WebSocket 连接成功后,我在 Postman 中将 Message 类型设置为 JSON,并发送如下数据
[238,239]- 期待的输出结果:Received: [238,239], type: object, length: 2
- 实际的输出结果:Received: [238,239], type: object, length: 9
- 疑惑点在于:
- typeof message === “object” 看起来像是对象
- 但 length = 9,却更像是字符串长度
- 为什么不是数组长度 2?
3. 相关代码
const ws = require('ws');
const server = new ws.Server({ port: 8080 });
server.on('connection', (socket) => {
console.log('New client connected');
socket.on('message', (message) => {
//输出结果:Received: [238,239], type: object, length: 9
console.log(`Received: ${message}, type: ${typeof message}, length: ${message.length}`);
socket.send(`Echo: ${message}`);
});
socket.on('close', () => {
console.log('Client disconnected');
});
});
console.log('WebSocket server is running on ws://localhost:8080');
二、为什么 length 会“不符合预期”?
这个问题的根因,其实是 “WebSocket 层 + Node.js ws 模块的默认行为” 叠加造成的。
1️⃣:Node.js的ws默认行为
- 在
ws中:客户端发送过来的 WebSocket 消息,默认会被解析为 Buffer - 而在
js中:typeof Buffer === 'object' - 验证方式:
console.log(message instanceof Buffer);,结果为true。(这解释了为什么 typeof message 是 object,但它并不是我以为的「JSON 对象」。)
2️⃣:WebSocket协议层没有Object/JSON的概念
WebSocket 完全不知道什么是 JSON
JSON 只是“文本内容的一种约定格式”,而不是传输类型
- WebSocket 在协议层只有两种数据类型:
- Text Frame(文本帧)
- Binary Frame(二进制帧)
3️⃣:Postman 的 “JSON” 设置到底做了什么?
- 当我在Postman里选择JSON并发送
[238,239] - Postman实际做的事情是
JSON.stringify([238,239]),也就是把我写的message进行了string - 然后以Text Frame把字符串
"[238,239]"发送出去
4️⃣ 为什么 length 是 9?
- 因为Node收到的是Buffer,"[238,239]"字节长度刚好是9
➡️ 本质是 Buffer + 文本帧造成的误解
三、正确的处理方式:显式 JSON 解析
- 既然 WebSocket 不会自动帮我们处理 JSON,那么就要在应用层手动解析。
socket.on('message', (message) => {
const data = JSON.parse(message);
});
四、衍生的JSON解析问题
默认代码是加完了JSON.parse(message);
在加上 JSON.parse(message) 之后,又引出了一个新疑问
1. 先说结论
JSON.parse并不是“只能解析object/array”- 它可以解析的是任何合法的JSON值
2. 我的误区
2.1 传入234数字后,JSON.parse(message)会报错?
- 结果👉:没有报错
2.2 JSON只能解析"{}“和”[]"?
- ❌实际并不是
3. JSON≠ Object(这是核心误区)
3.1 合法的JSON值(都不会报错)
这六种进行JSON解析都不会报错
| 类型 | 示例 |
|---|---|
| object | { "a": 1 } |
| array | [1, 2, 3] |
| string | "hello" |
| number | 238 |
| boolean | true |
| null | null |
3.2 非法的JSON(会直接抛异常)
JSON.parse(hello) // 没引号
JSON.parse('undefined') // JSON 里没有 undefined
JSON.parse('{a:1}') // key 没加引号
JSON.parse("'abc'") // 单引号
JSON.parse('238,239') // 不是一个完整 JSON 值
3.3 不会报错,但不是我想要的
JSON.parse('238') // → 238
JSON.parse('"238"') // → "238"
JSON.parse('true') // → true
JSON.parse('null') // → null
五、最终防御式写法(生产建议)
前提假设
- 我只接受 {} 形式的 JSON
- 不信任任何客户端输入
- 永远不要假设 JSON.parse 出来的是 object
✅ 至此,所有坑都被显式封死。
let msg;
try {
msg = JSON.parse(message);
} catch {
socket.send(JSON.stringify({
type: 'error',
payload: 'Invalid JSON'
}));
return;
}
if (typeof msg !== 'object' || msg === null) {
socket.send(JSON.stringify({
type: 'error',
payload: 'Message must be a JSON object'
}));
return;
}
更多推荐





所有评论(0)