Node.js视频流传输时同步发送JSON数据的实现方案问询
在Express视频流接口中同步发送坐标JSON数据(无需新增接口)
问题背景
我现在有个Express接口能流式传输本地MP4视频,想在不新增任何接口的前提下,同时向前端发送x、y坐标的JSON数据。目前的代码如下:
const express = require("express") const fs = require("fs") const app = express() app.get("/video", (req, res) => { const path = "video.mp4"; const stat = fs.statSync(path); const fileSize = stat.size; const head = { 'Content-Length': fileSize, 'Content-Type': 'video/mp4' } res.writeHead(200, head); fs.createReadStream(path).pipe(res); }); app.listen(3000, function () { console.log('App is running on port 3000') })
解决方案:使用Multipart混合响应
要在同一个接口里同时传输视频流和JSON数据,你可以利用HTTP的multipart/mixed响应类型——把视频内容和坐标数据拆分成独立的"部分",用一个自定义分隔符分隔,前端就能分别解析这两部分内容了。
下面是修改后的完整代码:
const express = require("express"); const fs = require("fs"); const app = express(); app.get("/video", (req, res) => { const videoPath = "video.mp4"; const videoStat = fs.statSync(videoPath); const videoSize = videoStat.size; // 生成一个唯一的分隔符,避免和内容里的字符串冲突 const boundary = `video-coord-separator-${Date.now()}`; // 设置响应头为multipart/mixed,指定分隔符 res.writeHead(200, { "Content-Type": `multipart/mixed; boundary=${boundary}`, "Transfer-Encoding": "chunked" // 启用分块传输,适配流式内容 }); // 先发送坐标JSON部分 res.write(`\r\n--${boundary}\r\n`); res.write('Content-Type: application/json\r\n\r\n'); // 这里替换成你的实际坐标数据,如果是实时的可以改成动态生成 const coordData = JSON.stringify({ x: 150, y: 300 }); res.write(coordData); // 再发送视频流部分 res.write(`\r\n--${boundary}\r\n`); res.write(`Content-Type: video/mp4\r\nContent-Length: ${videoSize}\r\n\r\n`); const videoStream = fs.createReadStream(videoPath); videoStream.on("end", () => { // 所有内容发送完毕后,加上结束标记 res.write(`\r\n--${boundary}--\r\n`); res.end(); }); // 把视频流管道到响应,注意不要自动结束响应 videoStream.pipe(res, { end: false }); }); app.listen(3000, () => { console.log('App is running on port 3000'); });
前端怎么解析这个响应?
前端需要手动拆分multipart响应的各个部分,这里用fetch举个例子:
async function loadVideoAndCoords() { const response = await fetch('/video'); const contentType = response.headers.get('Content-Type'); const boundary = contentType.split('boundary=')[1]; const body = await response.text(); // 按分隔符拆分各个部分 const parts = body.split(`\r\n--${boundary}`).filter(part => part.trim() !== ''); // 提取坐标JSON const coordPart = parts.find(part => part.includes('application/json')); const coords = JSON.parse(coordPart.split('\r\n\r\n')[1]); console.log('收到坐标:', coords); // 提取视频内容并渲染 const videoPart = parts.find(part => part.includes('video/mp4')); const videoBlob = new Blob([videoPart.split('\r\n\r\n')[1]], { type: 'video/mp4' }); const videoElement = document.querySelector('video'); videoElement.src = URL.createObjectURL(videoBlob); } loadVideoAndCoords();
额外提示
- 如果你的坐标数据是实时动态更新的(比如随着视频播放持续发送新坐标),可以把坐标拆成多个小的multipart部分,在视频流传输过程中随时发送,前端监听响应流的chunk就能实时获取新数据。
- 分隔符一定要唯一,用随机字符串加时间戳的方式能有效避免和内容冲突。
- 启用
Transfer-Encoding: chunked很重要,因为我们没法提前知道整个响应的总大小(尤其是动态发送坐标的情况)。
内容的提问来源于stack exchange,提问作者Mehmet Ali
相关产品推荐
相关产品推荐

