如何在Express(Node.js)中处理Blob并保存前端上传的录屏视频文件
解决方案
问题根因
- Express默认未开启二进制请求体解析,默认req.body为空
- 原有代码每次readable事件触发时都新建写入流,会覆盖之前写入的内容,仅能保存最后一段二进制数据
- 未监听请求结束事件,也未给前端返回响应,会触发请求超时
- MediaRecorder输出格式与存储后缀不匹配的话,会导致保存的文件无法正常播放
修复后实现代码
前端优化(可选,提升兼容性)
// 优先匹配H264编码的MP4格式,兼容性更好 const supportedMime = MediaRecorder.isTypeSupported('video/mp4; codecs=h264') ? 'video/mp4; codecs=h264' : 'video/webm'; // 原有MediaRecorder初始化时传入指定格式 // const recorder = new MediaRecorder(stream, { mimeType: supportedMime }) // 原有录制逻辑... const blob = new Blob(chunks, { type: supportedMime }); const savedVideo = document.getElementById("savedVideo"); chunks = []; const videoURL = window.URL.createObjectURL(blob); savedVideo.src = videoURL; // 停止所有轨道 stream.getTracks().forEach(track => track.stop()); // 上传Blob const response = await fetch('http://localhost:3001/upload', { method: 'POST', headers: { 'Content-Type': supportedMime, }, body: blob }); const uploadResult = await response.json(); console.log(uploadResult);
服务端代码
常规小文件场景直接用express.raw解析:
const express = require("express"); const cors = require('cors'); const fs = require('fs'); const path = require('path'); const app = express(); const port = 3001; app.use(cors({ origin: 'http://localhost:3000' })); // 开启二进制请求体解析,大小限制可根据实际需求调整 app.use(express.raw({ type: ['video/*'], limit: '200mb' })); app.post("/upload", (req, res) => { // 直接获取解析后的完整二进制Buffer const videoBuffer = req.body; // 生成唯一文件名避免覆盖,后缀和前端录制格式保持一致 const savePath = path.join(__dirname, `record_${Date.now()}.mp4`); fs.writeFile(savePath, videoBuffer, (err) => { if (err) { console.error('视频保存失败:', err); return res.status(500).json({ success: false, message: '保存失败' }); } res.json({ success: true, message: '保存成功', path: savePath }); }); }); app.listen(port, () => { console.log(`服务启动成功:http://localhost:${port}`); });
大文件场景优化方案(长时间录屏)
如果录制的视频文件过大,用内存缓存完整Buffer会占用过高资源,可直接用流管道写入:
app.post("/upload", (req, res) => { const savePath = path.join(__dirname, `record_${Date.now()}.mp4`); const writeStream = fs.createWriteStream(savePath); // 直接将请求流导入写入流 req.pipe(writeStream); writeStream.on('finish', () => { res.json({ success: true, message: '保存成功', path: savePath }); }); writeStream.on('error', (err) => { console.error('写入失败:', err); res.status(500).json({ success: false, message: '保存失败' }); }); });
内容的提问来源于stack exchange,提问作者Chicha
相关产品推荐
相关产品推荐

