You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Node.js向React.js传输视频列表并实现前端播放?

问题描述

Node.js后端从Google Cloud存储获取视频并返回的接口代码:

app.get("/getGalleryVideos", async (req, res) => {
  const [files] = await bucket.getFiles(bucketName, { prefix: req.query.user });
  const fileNames = files.map((file) => file.name);

  const sumFiles = [];
  for (let i = 0; i < fileNames.length; i++) {
    await bucket
      .file(fileNames[i])
      .download()
      .then((data) => {
        sumFiles.push(data);
      });
  }
  res.json(sumFiles);
});

React前端接收响应并尝试转换为video可用格式的测试代码:

function getGalleryVideos() {
    var user = "undefined";
    if (typeof Cookies.get("loggedInUser") != "undefined") {
      user = Cookies.get("loggedInUser");
    }
    axios({
      method: "get",
      url: `http://localhost:3001/getGalleryVideos`,
      params: {
        user: user,
      },
      timeout: 100000,
    }).then((res) => {
      console.log("res");
      console.log(res);
      console.log("res.data");
      console.log(res.data);
      console.log("res.data[1]");
      console.log(res.data[1]);
      console.log("res.data[1][0]");
      console.log(res.data[1][0]);
      console.log("res.data[1][0].data");
      console.log(res.data[1][0].data);

      const vid = new Blob(res.data[1][0].data, { type: "video/mp4" });

      console.log("vid");
      console.log(vid);
      console.log("url");
      console.log(URL.createObjectURL(vid));
      setVideo(URL.createObjectURL(vid));
    });
  }

出现的问题:转换为Blob前缓冲区大小为773491,转换后变为1987122,数据体积异常膨胀,生成的URL无法正常播放视频。


修复方案及优化方案

一、修复现有代码问题

问题核心:后端用res.json()返回二进制数据时,JSON会自动将Buffer转为Base64字符串,前端接收后转Blob时会出现数据损坏和体积膨胀。

后端修改

改为流式传输单个视频,同时返回视频列表让前端按需请求:

// 接口1:返回用户的视频列表(文件名+请求地址)
app.get("/getGalleryVideoList", async (req, res) => {
  const [files] = await bucket.getFiles(bucketName, { prefix: req.query.user });
  const videoList = files.map(file => ({
    name: file.name,
    requestUrl: `/getSingleVideo?file=${encodeURIComponent(file.name)}`
  }));
  res.json(videoList);
});

// 接口2:单个视频的流式传输接口
app.get("/getSingleVideo", async (req, res) => {
  const fileName = decodeURIComponent(req.query.file);
  const file = bucket.file(fileName);

  // 设置正确的视频响应头
  res.setHeader("Content-Type", "video/mp4");
  
  // 直接用流传输,避免占用过多服务器内存
  const readStream = file.createReadStream();
  readStream.pipe(res);

  // 处理流错误
  readStream.on("error", () => {
    res.status(500).send("视频加载失败");
  });
});

前端修改

先获取视频列表,再请求单个视频并指定responseType: 'blob'直接接收Blob:

function getGalleryVideos() {
  const user = Cookies.get("loggedInUser") || "undefined";
  // 先获取视频列表
  axios.get(`http://localhost:3001/getGalleryVideoList`, {
    params: { user }
  }).then(listRes => {
    // 取第一个视频测试
    const firstVideoUrl = listRes.data[0].requestUrl;
    // 请求单个视频,指定返回Blob类型
    axios.get(firstVideoUrl, {
      responseType: 'blob',
      timeout: 100000
    }).then(vidRes => {
      const videoUrl = URL.createObjectURL(vidRes.data);
      setVideo(videoUrl);
    }).catch(err => {
      console.error("视频加载失败:", err);
    });
  }).catch(err => {
    console.error("视频列表获取失败:", err);
  });
}

二、更优的视频传输方案

1. 直接返回GCS签名URL

无需后端中转视频流,后端生成带有效期的Google Cloud存储签名URL,前端直接从GCS下载视频,大幅降低服务器压力:

app.get("/getSignedVideoUrls", async (req, res) => {
  const [files] = await bucket.getFiles(bucketName, { prefix: req.query.user });
  // 批量生成签名URL
  const signedUrls = await Promise.all(files.map(async file => {
    const [url] = await file.getSignedUrl({
      action: "read",
      expires: "03-01-2025" // 设置URL有效期,格式为MM-DD-YYYY
    });
    return {
      name: file.name,
      playUrl: url
    };
  }));
  res.json(signedUrls);
});

前端直接使用签名URL作为video标签的src:

function getGalleryVideos() {
  const user = Cookies.get("loggedInUser") || "undefined";
  axios.get(`http://localhost:3001/getSignedVideoUrls`, {
    params: { user }
  }).then(res => {
    // 取第一个视频测试
    setVideo(res.data[0].playUrl);
  }).catch(err => {
    console.error("签名URL获取失败:", err);
  });
}

2. 流媒体传输(大视频场景)

如果视频体积较大,建议使用HLS/DASH流媒体协议。Google Cloud存储支持直接托管流媒体文件,后端可生成对应的播放列表URL,前端使用video.js等专用库进行播放,实现分段加载、清晰度切换等功能。


内容的提问来源于stack exchange,提问作者Ameen Izhac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 01:15:50