直接发送blob音频流需确保websocket连接就绪、mediarecorder正常启动并正确分片,后端须区分文本与二进制帧、按序拼接并规范生成wav文件。

直接发 File 或 Blob 就能传音频流,不用转 base64、不手动构造 ArrayBuffer,但必须处理好连接状态、分片节奏和后端 Buffer 拼接逻辑。
WebSocket发送Blob音频数据前必须检查的三件事
浏览器允许直接 ws.send(file),但实际传输失败往往不是代码写错,而是卡在连接准备环节:
-
ws.readyState必须为WebSocket.OPEN;onopen回调里发,或加轮询判断,别在onmessage里盲目发 - 音频采集用
MediaRecorder时,确保start()已调用且未触发error事件(比如用户拒授麦克风) - 若服务端要求鉴权,不要依赖 Cookie(WebSocket 不带跨域 Cookie),改用
Sec-WebSocket-Protocol头传 token,或首次发一个文本帧带{ "auth": "xxx" }
用 MediaRecorder 分块导出 Blob 并发送的实操要点
不能等整段录音结束再发——那样就不是“流式”了。关键在 ondataavailable 的触发时机和 Blob 类型设置:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 初始化时指定
mimeType: "audio/webm;codecs=opus"(Chrome/Firefox 兼容好),避免用audio/wav(默认生成大体积无压缩数据) - 调用
mediaRecorder.start(200),200ms 为每块间隔,太短(如 50ms)易触发高频 GC,太长(如 2s)失去流式意义 -
ondataavailable回调中拿到event.data是Blob,直接ws.send(event.data)即可,无需new Blob([event.data])套娃 - 移动端需注意:Safari 对单次
send()的Blob大小敏感,超过 1MB 可能卡顿,建议上限设为 512KB,超限时用slice()拆分
后端接收二进制帧时如何区分音频块与控制帧
WebSocket 协议本身不定义业务语义,ws 库(Node.js)或 @ServerEndpoint(Java)收到的数据类型取决于前端发什么:
- 前端发
JSON.stringify({ type: "start", sampleRate: 16000 })→ 后端event.data是字符串,typeof event.data === "string" - 前端发
file或new Blob([...])→ 后端收到的是Buffer(Node)或ByteBuffer(Java),event.isBinary为true - 不要混用:同一连接里,文本帧和二进制帧交替发送是合法的,但后端必须按顺序收——先收控制帧(如
{ "start": true }),再收后续所有二进制帧,直到收到{ "end": true } - Java 示例中,
@OnMessage方法要重载两个:一个参数为String,一个为ByteBuffer,否则二进制帧会被忽略或报错
音频流拼接与保存为 WAV 文件的关键陷阱
后端收到的是一堆零散 Buffer,直接写磁盘会得到一堆无法播放的碎片。WAV 头部必须最后写,且需提前知道总长度:
- 别用
fs.appendFile()累加——WAV 头部含文件总大小字段,必须在写完全部音频数据后回填 - 推荐流式处理:用
fs.createWriteStream()写入临时文件,同时用crypto.createHash("md5")流式计算校验值,避免全量加载内存 - WAV 格式要求:RIFF 头 + fmt 子块(固定 24 字节)+ data 子块(含真实音频字节),data 子块长度字段必须是音频数据长度 + 8(data 头部本身占 8 字节)
- 如果前端用 Opus 编码(webm 容器),后端不能直接当 WAV 写——要么转码(用
ffmpeg.wasm或服务端ffmpeg),要么前端改用audio/mp4;codecs=mp4a.40.2并约定服务端解封装
真正难的不是“怎么发”,而是“怎么让每一块都按时抵达、不丢不乱、能对齐时间轴”。音频流对帧序和时延敏感,一旦后端拼错了顺序或漏了一块,出来的就是咔哒声或静音段——这些细节不会报错,但会毁掉整个体验。










