Node.js 18生成视频Blob后客户端无法使用问题求助
问题描述
我正在学习Node.js和Blob,尝试在Node.js中从视频文件创建Blob,并将其通过JSON发送至客户端,数据将在Next.js的GetStaticProps中获取。以下是我在Node.js服务端编写的代码:
const fileBuffer = fs.readFileSync(filePath); // Path is something like example.com/video.mp4 const blob = new Blob([fileBuffer], { type: 'video/mp4' }); blobUrl = URL.createObjectURL(blob); // Return blob:nodedata:c3b1baf2-fba8-404f-8d3c-a1184a3a6db2代码返回的内容为:
blob:nodedata:c3b1baf2-fba8-404f-8d3c-a1184a3a6db2但我无法在客户端使用该URL,
<video src="blob:nodedat...">无法正常工作,肯定是哪里出错了?
问题根源
Node.js环境中的Blob是v18+版本新增的实现,和浏览器端的Blob属于完全独立的运行环境对象。服务端通过URL.createObjectURL生成的blob:nodedata:... URL仅在当前Node.js进程内部有效,客户端浏览器无法识别该协议的地址,自然无法加载对应的视频资源。
可行解决方案
方案1:直接使用静态资源路径(Next.js推荐)
如果视频文件放在Next.js项目的public目录下,直接在GetStaticProps中返回文件的相对路径,客户端直接用该路径作为video的src即可,Next.js会自动处理静态资源的托管和访问。
服务端(GetStaticProps)代码:
export async function getStaticProps() { // 假设视频文件在public/videos/example.mp4 const videoPath = '/videos/example.mp4'; return { props: { videoPath } }; }
客户端组件代码:
export default function VideoPage({ videoPath }) { return <video src={videoPath} controls />; }
方案2:将二进制数据转为Base64传递
如果必须通过JSON传递视频数据,可以将服务端的文件Buffer转为Base64格式,客户端接收后再转回Blob并生成浏览器可用的Object URL。
服务端代码:
import fs from 'fs'; export async function getStaticProps() { const filePath = './public/videos/example.mp4'; const fileBuffer = fs.readFileSync(filePath); // 转为Base64格式的data URL const base64Video = `data:video/mp4;base64,${fileBuffer.toString('base64')}`; return { props: { base64Video } }; }
客户端组件代码:
import { useRef, useEffect } from 'react'; export default function VideoPage({ base64Video }) { const videoRef = useRef(null); useEffect(() => { if (!base64Video || !videoRef.current) return; // 解析Base64数据并转为Blob const [, base64Data] = base64Video.split(','); const byteCharacters = atob(base64Data); const byteArray = new Uint8Array(byteCharacters.length); for (let i = 0; i < byteCharacters.length; i++) { byteArray[i] = byteCharacters.charCodeAt(i); } const blob = new Blob([byteArray], { type: 'video/mp4' }); const blobUrl = URL.createObjectURL(blob); videoRef.current.src = blobUrl; // 组件卸载时释放Blob URL,避免内存泄漏 return () => URL.revokeObjectURL(blobUrl); }, [base64Video]); return <video ref={videoRef} controls />; }
方案3:通过API路由返回视频流
如果视频文件较大,Base64会导致数据体积增大30%,此时可以创建Next.js API路由,直接返回视频文件的流,客户端用API地址作为video的src。
创建pages/api/video.js:
import fs from 'fs'; import path from 'path'; import { createReadStream } from 'fs'; export default function handler(req, res) { const filePath = path.join(process.cwd(), 'public/videos/example.mp4'); const stat = fs.statSync(filePath); res.writeHead(200, { 'Content-Type': 'video/mp4', 'Content-Length': stat.size, }); const stream = createReadStream(filePath); stream.pipe(res); }
客户端组件代码:
export default function VideoPage() { return <video src="/api/video" controls />; }
内容的提问来源于stack exchange,提问作者Lucas

