麦克风录制Blob分块流式上传后端:动态添加Blob至流的实现问询
实现边录边传音频(逐Blob流式发送)
核心思路
利用浏览器的MediaRecorder分段获取音频Blob,通过自定义ReadableStream将Blob持续注入流中,再用Axios把这个流作为请求体发送给后端——这样就能在用户结束录制前就开始传输数据,节省等待时间。
具体实现步骤
1. 初始化媒体录制
先获取用户麦克风权限,创建MediaRecorder实例,监听ondataavailable事件来获取分段Blob:
// 存储待发送的Blob队列 const blobQueue = []; let mediaRecorder; // 获取麦克风流并初始化录制 async function startRecording() { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); mediaRecorder = new MediaRecorder(stream); // 每段数据可用时,加入队列 mediaRecorder.ondataavailable = (e) => { if (e.data.size > 0) { blobQueue.push(e.data); } }; mediaRecorder.start(1000); // 每1秒生成一个Blob(可根据需求调整间隔) }
2. 创建可动态添加Blob的ReadableStream
自定义一个ReadableStream,它会从blobQueue中取出Blob,转换成二进制数据后推送给流:
function createBlobStream() { return new ReadableStream({ async pull(controller) { // 如果队列里有Blob,就取出处理 if (blobQueue.length > 0) { const blob = blobQueue.shift(); const arrayBuffer = await blob.arrayBuffer(); const uint8Array = new Uint8Array(arrayBuffer); controller.enqueue(uint8Array); } else if (mediaRecorder.state === 'inactive') { // 录制已结束且队列空,关闭流 controller.close(); } else { // 队列空但还在录制,等待100ms再检查 await new Promise(resolve => setTimeout(resolve, 100)); this.pull(controller); } }, cancel() { // 取消时清空队列 blobQueue.length = 0; } }); }
3. 用Axios发送流式请求
Axios支持将ReadableStream作为请求体(需确保浏览器/后端支持流式传输),直接发起POST请求:
async function startStreamingUpload() { const stream = createBlobStream(); try { await axios.post('/api/upload-audio', stream, { headers: { 'Content-Type': 'audio/webm', // 对应MediaRecorder的输出格式,可根据实际调整 'Transfer-Encoding': 'chunked' // 告诉后端这是分块传输 }, // 禁用Axios的自动转换,直接传递流 transformRequest: [(data) => data] }); console.log('音频上传完成'); } catch (error) { console.error('上传失败:', error); // 失败时停止录制 mediaRecorder.stop(); } }
4. 控制录制与上传的流程
// 开始录制+启动上传 async function start() { await startRecording(); startStreamingUpload(); } // 结束录制 function stopRecording() { if (mediaRecorder && mediaRecorder.state !== 'inactive') { mediaRecorder.stop(); } }
注意事项
- 后端兼容性:后端需要支持分块传输(
Transfer-Encoding: chunked),并能接收流式的音频数据进行拼接存储。 - 格式一致性:确保
MediaRecorder的输出格式(如audio/webm)和请求头的Content-Type一致,后端也要能处理该格式。 - 错误处理:如果上传中断,要及时停止录制并清理资源;同时要处理用户拒绝麦克风权限的情况。
- 浏览器支持:
ReadableStream和MediaRecorder在现代浏览器中都已支持,但需注意旧版浏览器的兼容性。
内容的提问来源于stack exchange,提问作者Oreste Viron
相关产品推荐
相关产品推荐

