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

Node.js将Flutter上传的octet-stream流转为MP4上传至GCP Cloud Storage

首先明确两个核心认知:

  1. application/octet-stream 只是通用二进制流的标识,你客户端上传的本身就是MP4格式的二进制数据,不需要做额外的格式转换。只要上传到GCS时指定正确的content-type元数据,存储后的文件就是可正常播放的MP4文件。
  2. 你之前req.pipe(blobStream)失效的绝大多数原因,是你所用的Node服务框架(比如Express)全局挂载了express.json()、express.urlencoded()这类请求体解析中间件,这类中间件会提前消费完req流的所有数据,导致后续pipe时流已经为空。

前置配置

如果你用的是Express框架,需要给上传接口单独排除通用的请求体解析中间件,确保req是未被消费的原始流:

// 该路由不要使用全局的express.json()、express.urlencoded()等中间件
app.post('/upload-video', (req, res) => {
  // 上传逻辑写在这个路由处理函数内
})

方案1:修复pipe逻辑(更推荐)

pipe会自动处理流的背压、数据传输顺序,不需要手动管理分块,是最简洁稳定的实现:

const { Storage } = require('@google-cloud/storage');
const storage = new Storage();

app.post('/upload-video', async (req, res) => {
  try {
    const newFileName = 'newFile.mp4'; // 建议添加.mp4后缀,避免后续文件识别异常
    const bucket = storage.bucket('dev.appspot.com/postVideos');
    const blob = bucket.file(newFileName);
    const blobStream = blob.createWriteStream({
      metadata: { contentType: 'video/mp4' },
      resumable: false // 小于100M的文件可以关闭,大文件建议开启可恢复上传
    });

    // 直接将原始请求流管道到GCS的可写流
    req.pipe(blobStream);

    // 等待上传完成
    await new Promise((resolve, reject) => {
      blobStream.on('error', reject);
      blobStream.on('finish', resolve);
    });

    res.status(200).send('上传成功');
  } catch (err) {
    console.error('上传失败:', err);
    res.status(500).send('上传失败');
  }
});

方案2:手动监听data事件处理分块(适配你当前的写法)

如果你需要自行处理接收的chunk数据,直接将chunk写入GCS的可写流即可,流会自动按顺序拼接内容,所有数据接收完成后调用end方法结束上传:

// 接收分块数据并写入GCS流
req.on('data', (chunk) => {
  const canWrite = blobStream.write(chunk);
  // 处理背压:如果GCS流缓冲区已满,暂停接收请求数据,避免内存溢出
  if (!canWrite) {
    req.pause();
  }
});

// GCS流缓冲区排空后,恢复接收请求数据
blobStream.on('drain', () => {
  req.resume();
});

// 请求数据接收完成,结束GCS上传流
req.on('end', () => {
  blobStream.end();
  console.log('全部分块接收完成,GCS上传处理中');
});

额外注意事项

  • 大文件上传建议开启GCS的可恢复上传能力,只需要在createWriteStream配置中把resumable设为true,SDK会自动处理分块、断点续传逻辑,不需要你自己拆分管理分块。
  • 如果是客户端主动将文件拆分为多个请求上传,你需要给每个分块添加序号标识,服务端先将所有分块存储到临时路径,全部收齐后调用GCS的compose接口合并为一个完整文件即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 00:57:04