React TypeScript中Firebase Storage上传Base64视频失败求助
问题解决思路
核心问题拆解
- Firebase上传格式错误:你用
reader.readAsDataURL(blob)得到的newDataURL是完整的Data URI格式(带data:video/mp4;base64,前缀),但Firebase的uploadString方法指定'base64'格式时,只需要纯base64编码的内容,前缀里的data:、;base64这些字符属于无效格式,所以触发了storage/invalid-format错误。 - TypeScript类型不匹配:
reader.result的类型是string | ArrayBuffer,直接传给uploadString会因为类型不确定报错,需要先确保它是字符串类型再处理。 - 原代码的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
相关产品推荐
相关产品推荐

