You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在浏览器中区分WebSocket文本与二进制消息?

当然可以!既然你能同时控制WebSocket的服务端和客户端,区分JSON文本消息和JPEG二进制消息其实有好几种省心的方案,我给你挑几个最实用的:

方案1:利用WebSocket原生的消息类型区分(最推荐)

WebSocket本身就支持发送文本类型和二进制类型两种消息,这刚好匹配你的JSON(文本)和JPEG(二进制)场景,完全不需要修改数据包内容,是最简洁的方案。

服务端(Node.js)代码示例:

// 发送JSON文本消息(默认就是文本类型)
const jsonMessage = { status: "ok", data: "some info" };
ws.send(JSON.stringify(jsonMessage));

// 发送JPEG二进制消息(指定binary参数)
const fs = require('fs');
const jpegBuffer = fs.readFileSync('./target.jpg');
ws.send(jpegBuffer, { binary: true });

客户端代码示例:

ws.onmessage = (event) => {
  // 判断消息类型:字符串就是JSON文本
  if (typeof event.data === 'string') {
    try {
      const jsonData = JSON.parse(event.data);
      console.log('收到JSON消息:', jsonData);
      // 这里处理你的JSON逻辑
    } catch (e) {
      console.error('不是合法JSON的文本消息:', event.data);
    }
  } 
  // Blob/ArrayBuffer就是二进制JPEG
  else if (event.data instanceof Blob) {
    const imgUrl = URL.createObjectURL(event.data);
    const img = document.createElement('img');
    img.src = imgUrl;
    document.body.appendChild(img);
    // 记得用完释放URL,避免内存泄漏
    img.onload = () => URL.revokeObjectURL(imgUrl);
  }
};
方案2:自定义元数据前缀(兼容特殊场景)

如果因为某些限制没法用原生消息类型区分,你可以给每个数据包加个标识前缀,明确告诉客户端消息类型:

  • JSON消息前缀用[JSON],比如发送[JSON]{"type":"log","content":"hello"}
  • JPEG消息前缀用[JPEG],服务端把前缀Buffer和JPEG文件Buffer拼接后发送

服务端发送JPEG的示例:

const fs = require('fs');
const prefix = Buffer.from('[JPEG]');
const jpegBuffer = fs.readFileSync('./target.jpg');
const combinedBuffer = Buffer.concat([prefix, jpegBuffer]);
ws.send(combinedBuffer, { binary: true });

客户端处理示例:

async function parseMessage(event) {
  if (typeof event.data === 'string') {
    if (event.data.startsWith('[JSON]')) {
      const jsonStr = event.data.slice(6); // 去掉前缀
      const jsonData = JSON.parse(jsonStr);
      console.log('JSON消息:', jsonData);
    } else {
      console.log('普通文本消息:', event.data);
    }
  } else if (event.data instanceof Blob) {
    const buffer = await event.data.arrayBuffer();
    const uint8 = new Uint8Array(buffer);
    // 把前缀转成字符串判断
    const prefix = new TextDecoder().decode(uint8.slice(0, 6));
    if (prefix === '[JPEG]') {
      // 截取前缀后的部分作为JPEG数据
      const jpegBlob = new Blob([uint8.slice(6)]);
      const imgUrl = URL.createObjectURL(jpegBlob);
      // 后续显示图片逻辑...
    }
  }
}

ws.onmessage = parseMessage;
方案3:利用数据包本身的特征判断(兜底方案)

就是你提到的,JSON以{"开头、JPEG以FF D8 FF开头的特征,这个可以作为兜底方案,在没法用前两种方案时使用:

客户端判断示例:

async function isJpeg(blob) {
  const buffer = await blob.arrayBuffer();
  const uint8 = new Uint8Array(buffer);
  // JPEG的文件头签名:FF D8 FF
  return uint8.length >= 3 && uint8[0] === 0xFF && uint8[1] === 0xD8 && uint8[2] === 0xFF;
}

ws.onmessage = async (event) => {
  if (typeof event.data === 'string') {
    if (event.data.startsWith('{')) {
      // 处理JSON
      const json = JSON.parse(event.data);
      console.log(json);
    } else {
      // 其他纯文本
      console.log('文本消息:', event.data);
    }
  } else if (event.data instanceof Blob) {
    if (await isJpeg(event.data)) {
      // 显示JPEG
      const imgUrl = URL.createObjectURL(event.data);
      const img = document.createElement('img');
      img.src = imgUrl;
      document.body.appendChild(img);
    } else {
      console.log('其他二进制数据');
    }
  }
};

总的来说,方案1是最优解,它完全贴合WebSocket协议的设计,逻辑简洁且不容易出错。如果有特殊场景限制,再考虑方案2或3。

内容的提问来源于stack exchange,提问作者fadedbee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:19:24