使用Firebase 9的uploadBytesResumable上传图片时遇_throwIfRoot未定义错误
问题分析与解决方案
错误根源
你遇到的TypeError: Cannot read property '_throwIfRoot' of undefined以及上传无效小文件的问题,核心原因是错误地将本地文件路径直接转为Blob:
const blob = new Blob([image[0]]);
这里的image[0]是file://开头的本地文件路径字符串,直接用它创建Blob时,实际是把路径文本转成了二进制数据(大小仅为路径字符串的长度,也就是你看到的9字节左右),而非读取图片的真实二进制内容。这种无效的Blob传入Firebase Storage后,触发了内部方法调用错误。
修复方案
在React Native/Expo环境中,需要先通过网络请求读取本地文件的二进制内容,再转为Blob后上传。以下提供两种可行的实现方式:
方式1:使用原生fetch API(通用方案)
const uploadImage = async (image) => { if (!image || !image[0]) return; const imageRef = ref(storage, `images/${user.uid}/${v4()}`); try { // 通过fetch读取本地文件内容 const response = await fetch(image[0]); const blob = await response.blob(); console.log("有效Blob大小", blob.size); // 应与原图片大小一致 await uploadBytesResumable(imageRef, blob); console.log("图片上传成功"); } catch (error) { console.error(`上传失败:${error}`); } };
方式2:使用Expo FileSystem(Expo项目推荐)
如果你的项目基于Expo,用expo-file-system处理本地文件更高效:
import * as FileSystem from 'expo-file-system'; const uploadImage = async (image) => { if (!image || !image[0]) return; const imageRef = ref(storage, `images/${user.uid}/${v4()}`); try { // 先验证原文件信息 const fileInfo = await FileSystem.getInfoAsync(image[0], { size: true }); console.log("原文件大小", fileInfo.size); // 通过XMLHttpRequest读取文件并转为Blob const blob = await new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.onload = () => resolve(xhr.response); xhr.onerror = () => reject(new TypeError("读取文件失败")); xhr.responseType = "blob"; xhr.open("GET", image[0], true); xhr.send(null); }); await uploadBytesResumable(imageRef, blob); console.log("图片上传成功"); blob.close(); // 释放资源 } catch (error) { console.error(`上传失败:${error}`); } };
额外注意事项
- 验证Blob有效性:修复后打印
blob.size,应与原图片文件大小匹配,而非几十字节。 - 权限配置:确保已在
app.json中配置了图片访问权限(iOS的NSPhotoLibraryUsageDescription、Android的READ_EXTERNAL_STORAGE等)。 - 资源释放:上传完成后调用
blob.close()避免内存泄漏。
内容的提问来源于stack exchange,提问作者Samuel Bone
相关产品推荐
相关产品推荐

