一、遇到的问题

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 解析

  1. 既然 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;
}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐