websocket发送blob或file可直接传输二进制文件,无需转base64或arraybuffer,但须确保连接就绪(readystate===open)、分片合理(如≤512kb)、后端能按序拼接buffer。

WebSocket 传输二进制文件,send() 直接传 Blob 或 File 就行——不用转 base64,不手动构造 ArrayBuffer,但前提是连接就绪、分片合理、后端能按序拼接。
发送前必须确认的三件事
浏览器允许 ws.send(file),但失败往往卡在准备环节,不是代码写错了:
-
ws.readyState必须为WebSocket.OPEN;别在onmessage里盲目发,应在onopen回调中发,或加轮询判断 - 若用
MediaRecorder采集音频,确保已调用start()且没触发error事件(比如用户拒授麦克风) - 服务端若需鉴权,别依赖 Cookie(WebSocket 不带跨域 Cookie),改用
Sec-WebSocket-Protocol头传 token,或首次发一个文本帧如{"auth": "xxx"}
大文件要分片,不能整块 send
直接 send(blob) 对小文件没问题,但超过几 MB 就容易卡顿、内存暴涨甚至连接中断:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- Safari 对单次
send()的Blob大小敏感,超过 1MB 可能卡顿;建议上限设为 512KB - 用
blob.slice(start, end)拆分,例如:chunk = file.slice(i * 512 * 1024, (i + 1) * 512 * 1024) - 每发一块,建议附带简单元信息(如
{"seq": 0, "total": 12, "name": "demo.pdf"}),用文本帧先发,再发对应二进制帧 - 别在主线程做高分辨率图片处理+
toBlob()——挪到Worker里做,避免 UI 阻塞
后端接收时怎么区分 Blob 和控制帧
WebSocket 协议本身不定义业务语义,收到什么类型,完全取决于前端发什么:
- 前端发
JSON.stringify({type: "start"})→ 后端event.data是字符串,typeof === "string" - 前端发
file或new Blob([])→ 后端收到的是Buffer(Node.jsws库)或ByteBuffer(Java),且event.isBinary === true - 同一连接里文本帧和二进制帧可交替发送,但后端必须按顺序收:先收控制帧(如
{"start": true}),再收后续所有二进制帧,直到收到{"end": true} - Java 示例中,
@OnMessage方法必须重载两个:一个参数为String,一个为ByteBuffer,否则二进制帧会被忽略或报错
为什么 Blob 比 ArrayBuffer 更适合文件直传
两者都合法,但适用场景不同,选错会多绕弯子:
-
Blob是零拷贝发送,兼容 IE10+,适合用户选择的<input type="file">文件直传;File是Blob子类,ws.send(file)就是最简路径 -
ArrayBuffer适合需要精细控制字节的场景(如加协议头、加密),但需预处理;若只是传原始文件,额外调用file.arrayBuffer()再send(buffer)属于无谓转换 - 别把
canvas.toDataURL()结果再包一层 JSON 发——等于双重字符串化,纯属自找麻烦;应改用canvas.toBlob(callback, 'image/jpeg', 0.8) - 移动端弱网下易断连,
Blob分片方案必须配合已发偏移量缓存 + 重连逻辑,否则重传成本极高
真正难的不是“怎么发”,而是“怎么让每一块都稳稳落到后端、按序拼回去”。很多问题表面是前端 send 失败,实际是后端没正确识别 isBinary,或拼接时丢了某段 Buffer,又或者没处理好跨帧边界。这些细节,比选 Blob 还是 ArrayBuffer 更关键。










