当后端同事跟你说图片传输格式一定要用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-dataframe.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 只认字符串。
浙公网安备 33010602011771号