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

如何将含Blob数据的JavaScript对象序列化后通过WebSocket发送?

解决WebSocket发送包含Blob的序列化消息问题

直接发送Blob给WebSocket能正常工作,但用JSON.stringify封装Blob会失败,核心原因是JSON无法序列化Blob对象——Blob属于浏览器特有的二进制对象,JSON序列化时只会保留其原型链上的可枚举属性,最终得到{ type: 'REC', data: {} }这种无效结构,服务器自然无法解析。

下面提供三种可行的解决方案,按实现复杂度和效率排序:


方案1:将Blob转为Base64字符串封装到JSON

这是最直观的方法,把Blob转成Base64编码的字符串,就能被JSON正常序列化。

前端代码

recorder = new MediaRecorder(canvasStream);
recorder.ondataavailable = e => {
  const reader = new FileReader();
  // 读取Blob为DataURL格式
  reader.onload = function() {
    // 剔除DataURL前缀(如"data:video/webm;base64,"),只保留Base64内容
    const base64Data = reader.result.split(',')[1];
    // 封装成JSON对象发送
    ws.send(JSON.stringify({ type: 'REC', data: base64Data }));
  };
  reader.readAsDataURL(e.data);
};

服务器端处理(以Node.js为例)

接收后解析JSON,再将Base64转回二进制:

ws.on('message', (message) => {
  const msg = JSON.parse(message);
  if (msg.type === 'REC') {
    // 将Base64转为Buffer(二进制数据)
    const blobBuffer = Buffer.from(msg.data, 'base64');
    // 后续处理逻辑...
  }
});

优缺点:实现简单,无需额外依赖;但Base64会让数据体积增加约33%,适合小体积的媒体片段。


方案2:自定义二进制帧(高效无体积损耗)

直接使用WebSocket的二进制发送能力,将消息类型和Blob数据打包成一个二进制帧,避免Base64的体积开销。

前端代码

recorder = new MediaRecorder(canvasStream);
recorder.ondataavailable = e => {
  const typeStr = 'REC';
  // 将类型字符串转为Uint8Array
  const typeEncoder = new TextEncoder();
  const typeUint8 = typeEncoder.encode(typeStr);

  // 读取Blob的ArrayBuffer
  e.data.arrayBuffer().then(blobBuffer => {
    // 计算总缓冲区大小:4字节存储类型长度 + 类型内容长度 + Blob数据长度
    const totalLength = 4 + typeUint8.length + blobBuffer.byteLength;
    const totalBuffer = new ArrayBuffer(totalLength);
    const dataView = new DataView(totalBuffer);

    // 写入类型长度(32位无符号整数,小端字节序)
    dataView.setUint32(0, typeUint8.length, true);
    // 写入类型内容
    new Uint8Array(totalBuffer, 4, typeUint8.length).set(typeUint8);
    // 写入Blob二进制数据
    new Uint8Array(totalBuffer, 4 + typeUint8.length).set(new Uint8Array(blobBuffer));

    // 发送二进制帧
    ws.send(totalBuffer);
  });
};

服务器端处理(以Node.js为例)

解析二进制帧,先读取类型,再提取Blob数据:

ws.on('message', (buffer) => {
  const dataView = new DataView(buffer.buffer);
  // 读取前4字节得到类型长度
  const typeLength = dataView.getUint32(0, true);
  // 读取类型字符串
  const typeStr = new TextDecoder().decode(new Uint8Array(buffer.buffer, 4, typeLength));
  
  if (typeStr === 'REC') {
    // 提取Blob数据
    const blobBuffer = buffer.slice(4 + typeLength);
    // 后续处理逻辑...
  }
});

优缺点:数据无体积损耗,传输效率高;需要手动处理二进制编解码,逻辑稍复杂。


方案3:使用支持二进制的序列化库(如MessagePack)

MessagePack是一种高效的二进制序列化格式,原生支持二进制数据,比JSON更紧凑,且无需手动处理编码。

前端代码(需引入msgpack-lite库)

import msgpack from 'msgpack-lite';

recorder = new MediaRecorder(canvasStream);
recorder.ondataavailable = async e => {
  // 将Blob转为Uint8Array
  const blobBuffer = new Uint8Array(await e.data.arrayBuffer());
  // 序列化包含类型和数据的对象
  const packedData = msgpack.encode({ type: 'REC', data: blobBuffer });
  // 发送二进制数据
  ws.send(packedData);
};

服务器端处理(Node.js)

const msgpack = require('msgpack-lite');

ws.on('message', (buffer) => {
  const msg = msgpack.decode(buffer);
  if (msg.type === 'REC') {
    // msg.data 就是Uint8Array格式的二进制数据
    const blobBuffer = Buffer.from(msg.data);
    // 后续处理逻辑...
  }
});

优缺点:兼顾易用性和效率,无需手动处理二进制编解码;但需要前后端引入相同的序列化库。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 15:00:18