Node.js推送FFmpeg进度至客户端时出现报错求助
问题修复方案
问题根源
- 服务端响应冲突:先用
res.write发送分块进度数据(SSE格式),后续又调用res.json返回结果。res.json会自动设置响应头并结束响应,但此时响应已处于分块传输状态,导致重复发送响应头,触发ERR_HTTP_HEADERS_SENT错误。 - 客户端处理方式错误:普通
axios.then只能处理完整JSON响应,无法接收流式SSE数据,因此出现net::ERR_INCOMPLETE_CHUNKED_ENCODING错误。
服务端代码修复
统一使用Server-Sent Events (SSE) 格式发送进度和最终结果,确保响应头一致并正确结束连接:
// 提前设置SSE响应头,必须在任何res.write之前调用 res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' }); // 进度监听逻辑 ffmpeg.stderr.on('data', (data) => { if (timeMatch) { const progress = Math.floor((currentTime / duration) * 100); console.log(`FFmpeg in progress : ${progress}%`); // 按SSE格式发送进度数据 res.write(`data: ${JSON.stringify({ progress })}\n\n`); } }); // 处理完成后的逻辑(移除多余的fs.readFile,bucket.upload无需提前读取文件) ffmpeg.on("close", async () => { try { const result = await bucket.upload(outputPath); if (result) { // 按SSE格式发送最终媒体链接 res.write(`data: ${JSON.stringify({ mediaLink: `https://firebasestorage.googleapis.com/${fileName}?alt=media&token=${idtoken}` })}\n\n`); } else { res.write(`data: ${JSON.stringify({ error: 'Error: could not get media link' })}\n\n`); } // 结束响应 res.end(); } catch (err) { res.write(`data: ${JSON.stringify({ error: err.message })}\n\n`); res.end(); } });
React客户端代码修复
使用EventSource接收SSE流式数据,替代普通axios请求:
// 发起SSE请求,替换为你的实际接口地址 const eventSource = new EventSource('/your-processing-api'); // 监听服务端发送的消息 eventSource.onmessage = (event) => { const data = JSON.parse(event.data); if (data.progress !== undefined) { console.log('Progress:', data.progress); // 更新UI进度条或其他状态 } else if (data.mediaLink) { console.log('Final data:', data.mediaLink); // 处理最终媒体链接逻辑 eventSource.close(); // 接收完成后关闭连接 } else if (data.error) { console.error('Error:', data.error); eventSource.close(); } }; // 监听连接错误 eventSource.onerror = (error) => { console.error('SSE connection error:', error); eventSource.close(); };
内容的提问来源于stack exchange,提问作者Youssef
相关产品推荐
相关产品推荐

