base64传媒体是性能瓶颈——体积增33%、多编解码、易断连;应优先用blob或arraybuffer,websocket.send()仅支持字符串/blob/arraybuffer/arraybufferview四种类型。

直接用 Base64 发图片或语音,90% 的性能问题是它引起的——体积涨 33%,前后端多一次编解码,还容易触发 WebSocket 帧超长断连。真要传,优先选 Blob 或 ArrayBuffer。
WebSocket.send() 支持哪些类型的数据
send() 只认四种原生类型:字符串、Blob、ArrayBuffer、ArrayBufferView(如 Uint8Array)。JSON 对象必须先 JSON.stringify();File 是 Blob 的子类,可直接 send;Base64 字符串本质是字符串,但属于“伪二进制”——浏览器不会自动识别为媒体数据,后端还得手动 Buffer.from(base64, 'base64')。
- 字符串:适合小文本、控制指令,或带
data:image/xxx;base64,前缀的调试用 Base64 -
Blob:零拷贝发送,兼容 IE10+,适合用户选择的input[type=file]文件直传 -
ArrayBuffer:需预处理(如 canvas 截图后ctx.getImageData().data.buffer),适合加协议头、分片、加密等场景 - 避免把
canvas.toDataURL()结果再包一层 JSON 发——这等于双重字符串化,纯属自找麻烦
前端发图片:跳过 toDataURL(),改用 toBlob() 或直接 send(File)
用户选图后,file 对象本身就是 Blob,不用转 Base64。如果需要缩放/裁剪,用 canvas.toBlob() 回调拿 Blob,比 toDataURL() 内存开销低一个数量级。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
-
const file = input.files[0]; socket.send(file);—— 最简路径,服务端收到的是原始二进制流 - 截图场景:
canvas.toBlob(blob => socket.send(blob), 'image/jpeg', 0.8);,注意 MIME 类型要和服务端约定一致 - 若需加帧头(如 4 字节长度 + 1 字节类型标识),先读取
Blob.arrayBuffer(),再用Uint8Array拼接,最后socket.send(new Uint8Array(merged).buffer) - 别在主线程做高分辨率 canvas 绘制+toBlob——卡顿明显,挪到
Worker里做
前端发语音:MediaRecorder + Blob 流式发送
语音不是静态文件,MediaRecorder 输出的是 Blob 片段,适合边录边发。关键点在于设置 binaryType = 'arraybuffer' 并监听 dataavailable 事件。
-
socket.binaryType = 'arraybuffer';必须在open后立刻设,否则收到的event.data是字符串 -
mediaRecorder.ondataavailable = e => { if (e.data.size > 0) socket.send(e.data); };——e.data是Blob,send()自动转二进制帧 - 服务端需按顺序拼接多个
Blob片段,不能当成独立文件处理;建议加简单帧头标明序号和总长度 - 别用
getUserMedia()录完再转 Base64——延迟高、内存爆、还丢实时性
服务端接收时如何区分图片和语音
靠 MIME 类型不可靠(Blob 不带 type,ArrayBuffer 更没 type),必须靠应用层协议。最轻量做法:前端发前加 1 字节类型标记(如 0x01 = 图片,0x02 = 语音),服务端用 Buffer.slice(0, 1) 判断。
- Node.js ws 库中:
ws.on('message', (data, isBinary) => { if (isBinary) { const buf = Buffer.isBuffer(data) ? data : Buffer.from(data); const type = buf.readUInt8(0); const payload = buf.slice(1); } }); - Spring Boot 中:
@OnMessage public void handleMessage(byte[] data, Session session),直接从data[0]读类型 - 切忌用
instanceof Blob或typeof判断前端发来的数据——服务端收不到Blob对象,只有原始字节 - Base64 方案里常写的
data.startsWith('data:image/')在二进制模式下根本不存在,那是字符串模式的遗留写法
真正难的不是怎么发,而是前后端对“一帧数据”的定义是否一致:有没有帧头、怎么分片、丢包怎么恢复、大文件要不要断点续传。这些不约好,光换 Blob 也救不了传输失败的问题。










