当后端同事跟你说图片传输格式一定要用Uint8Array,因为它的体积小,传输快,而商定的交互JSON格式压根不认识Uint8Array类型数据,这时候怎么办呢?
下面就教你为什么,怎么办,好好沟通,合作共赢。

一、先说结论:Uint8Array 永远不可能“原样进 JSON”

不存在「JSON 直接支持 Uint8Array」这件事

为什么后端会觉得可以?

他们脑子里通常是:

// 后端(Node.js)里的 Buffer
Buffer.from([1,2,3])

Node 里 Buffer 看起来像数组,于是想当然认为:

前端也有个 Uint8Array,那不就是一回事吗?

但真相是:

环境 本质
Node Buffer 二进制缓冲区
前端 Uint8Array TypedArray
JSON 纯文本协议

JSON 规范里只有:

  • string
  • number
  • boolean
  • object
  • array
  • null

👉 没有 binary


二、前端直接塞 Uint8Array 会发生什么?

你以为你在传:

{
  data: Uint8Array([1,2,3,4])
}

实际上浏览器会怎么处理?

JSON.stringify({
  data: Uint8Array([1,2,3,4])
})

结果:

{
  "data": {}
}

或者某些库里会变成:

{
  "data": {
    "0": 1,
    "1": 2,
    "2": 3,
    "3": 4
  }
}

灾难来了:

  • 一个 1MB 的 Uint8Array
  • 变成 { "0": 255, "1": 255, ... }
  • 体积直接 ×8 ~ ×12
  • 后端拿到的不是“二进制”,是“数字字典”

三、后端说“直接传”,你要给的 3 个可行方案

✅ 方案 1(最推荐):binary WebSocket(别用 JSON)

一句话:别用 JSON 传二进制

如果后端是 Node.js:

// 前端
ws.binaryType = 'arraybuffer';
ws.send(uint8Array.buffer);
// 后端(ws 库)
ws.on('message', (data) => {
  // data 本身就是 Buffer
  const buffer = data; // 不需要 parse
});

✅ 优点:

  • 零拷贝
  • 体积最小
  • 后端拿到的是真 Buffer

📌 话术:

“WebSocket 支持 binary frame,我们走 raw binary,不走 JSON,这是标准做法。”


✅ 方案 2:HTTP + FormData(后端最爱,但别用 JSON)

如果后端坚持“接口调用”:

const blob = new Blob([uint8Array], { type: 'application/octet-stream' });

const form = new FormData();
form.append('frame', blob, 'frame.bin');
form.append('width', 1280);
form.append('height', 720);

fetch('/upload', { method: 'POST', body: form });

后端:

req.file.buffer  // Node

✅ 优点:

  • 后端无脑收
  • 不用改认知

✅ 方案 3:Uint8Array → Base64,但只包一层 JSON

这是“后端最固执”时的妥协方案。

function uint8ToBase64(uint8) {
  let s = '';
  for (let i = 0; i < uint8.length; i++) {
    s += String.fromCharCode(uint8[i]);
  }
  return btoa(s);
}

const payload = {
  width: 1280,
  height: 720,
  format: 'gzip',
  data: uint8ToBase64(compressed)
};

ws.send(JSON.stringify(payload));

后端解:

Buffer.from(data, 'base64')

📌 明确告诉后端:

“这是 Base64 编码后的二进制,不是数组,不是对象。”


四、如果后端说“那我不管,你直接 JSON 里传 Uint8Array”

你可以反手甩一段无法反驳的代码

const a = new Uint8Array([1,2,3]);
console.log(JSON.stringify({ d: a }));
// 输出:{"d":{}}

然后问:

“你希望我怎么把一个 {} 还原成二进制?”


五、一个非常关键的“专业补刀”

告诉后端这件事:

WebSocket + JSON + 大二进制 = 反模式

RFC 6455 专门设计 binary frame,就是为了不让你干这件事。

你可以直接给这句:

“浏览器里 JSON 是文本协议,binary frame 才是二进制协议。
把 Uint8Array 塞 JSON,等于把文件用 Excel 打开再传。”


六、可以直接贴给后端的「对接文档」

如果你需要的话,可以直接对接给你的同事:


📌 前端 → 后端 二进制传输规范(建议)

方式一(实时帧,推荐)

  • 协议:WebSocket
  • 帧类型:binary
  • 前端发送:Uint8Array.buffer
  • 后端接收:Buffer
  • 无需 JSON.parse

方式二(HTTP)

  • multipart/form-data
  • frame.bin 为原始二进制
  • 附加字段用普通 form field

方式三(必须 JSON)

  • 数据先 gzip(pako.deflate
  • 再 Base64
  • 字段名:data
  • 同时传 encoding: gzip+base64

❌ 不支持的方式

  • 直接在 JSON 中传 Uint8Array
  • Array.from(uint8Array)
  • Object.keys 形式的像素数组

原因:体积膨胀 8–12 倍,且不可恢复语义。


七、总结

Uint8Array 不是数据格式,是内存视图。
它必须通过 binary frame / FormData / Base64 才能“出门”。
JSON 只认字符串。

posted on 2026-08-13 16:12  羽丫头不乖  阅读(1)  评论(0)    收藏  举报