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

React TypeScript中Firebase Storage上传Base64视频失败求助

问题解决思路

核心问题拆解

  1. Firebase上传格式错误:你用reader.readAsDataURL(blob)得到的newDataURL是完整的Data URI格式(带data:video/mp4;base64,前缀),但Firebase的uploadString方法指定'base64'格式时,只需要纯base64编码的内容,前缀里的data:、;base64这些字符属于无效格式,所以触发了storage/invalid-format错误。
  2. TypeScript类型不匹配:reader.result的类型是string | ArrayBuffer,直接传给uploadString会因为类型不确定报错,需要先确保它是字符串类型再处理。
  3. 原代码的Promise逻辑漏洞:你在reader.onloadend回调里返回videoStorageDownloadURL,但外层函数直接return 'notAvailable',这会导致函数提前返回,永远拿不到正确的下载链接——因为FileReader是异步操作,回调执行时外层函数已经结束了。

修复后的完整代码

const convertToVideoBlob = async (dataURL: string, storageRef: StorageReference): Promise<string> => {
  console.log("dataURL: ", dataURL);
  const promiseRes = await fetch(dataURL);
  const blob = await promiseRes.blob();

  // 把FileReader的异步操作包装成Promise,避免回调嵌套和提前返回问题
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = async () => {
      // 先判断result是否为字符串,处理TypeScript类型问题
      if (typeof reader.result !== 'string') {
        reject(new Error('读取Blob失败,结果不是字符串'));
        return;
      }
      const newDataURL = reader.result;
      console.log(`testing: ${newDataURL}`);
      console.log(`testing type: ${typeof(newDataURL)}`);

      // 提取纯base64内容:去掉data URI前缀
      const base64Content = newDataURL.split(',')[1];
      try {
        await uploadString(storageRef, base64Content, 'base64');
        const videoStorageDownloadURL = await getDownloadURL(storageRef);
        console.log("videoStorageDLlink: ", videoStorageDownloadURL);
        resolve(videoStorageDownloadURL);
      } catch (error) {
        reject(error);
      }
    };
    reader.onerror = () => {
      reject(reader.error);
    };
    reader.readAsDataURL(blob);
  });
};

关键修复点说明

  • 处理Data URI前缀:用split(',')[1]把data:video/mp4;base64,前缀去掉,只保留后面的纯base64编码内容,这样uploadString就能正确识别格式。
  • TypeScript类型安全:通过typeof reader.result !== 'string'的类型守卫,确保后续操作的是字符串,避免类型断言的不安全,也解决了类型报错。
  • 修复Promise逻辑:把FileReader的异步操作包装成一个新的Promise,在回调里用resolve返回正确的下载链接,用reject处理错误,这样外层函数就能正确等待异步操作完成,返回实际的下载URL,而不是提前返回'notAvailable'。

额外优化建议

其实你可以不用绕FileReader这一步,直接把Blob上传到Firebase,更简单高效:

const convertToVideoBlob = async (dataURL: string, storageRef: StorageReference): Promise<string> => {
  console.log("dataURL: ", dataURL);
  const promiseRes = await fetch(dataURL);
  const blob = await promiseRes.blob();
  
  await uploadBytes(storageRef, blob);
  const videoStorageDownloadURL = await getDownloadURL(storageRef);
  console.log("videoStorageDLlink: ", videoStorageDownloadURL);
  return videoStorageDownloadURL;
};

用uploadBytes直接上传Blob对象,省去了Data URI和base64转换的步骤,既避免了格式错误,也提升了性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 22:00:57