React Native Expo 上传文件到 Firebase Storage 出现网络请求失败如何解决?
问题描述
我在使用 Expo 开发 React Native 应用,尝试将文件上传到 Firebase Storage 时触发了警告,相关代码与报错信息如下:
设备文件选取函数
const pickDocument = async () => { let result = await DocumentPicker.getDocumentAsync({ // type: "application/pdf", }); if (result != null) { setfile(result); setfileName(result.name); seturi(result.uri); console.log(result); } };
文件上传函数
const uploadLessonSlide = async (uri) => { const blob = await new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.onload = function () { resolve(xhr.response); }; xhr.onerror = function (e) { console.log("error"); console.log(e); reject(new TypeError("Network request failed")); }; xhr.responseType = "blob"; xhr.open("GET", uri, true); xhr.send(null); }); const ref = storage.ref().child("images"); const snapshot = await ref.put(blob); blob.close(); return await snapshot.ref.getDownloadURL(); };
报错信息
控制台警告
[Unhandled promise rejection: TypeError: Network request failed] at node_modules/react-native/Libraries/Network/XMLHttpRequest.js:600:10 in setReadyState at node_modules/react-native/Libraries/Network/XMLHttpRequest.js:395:6 in __didCompleteResponse at node_modules/react-native/Libraries/vendor/emitter/EventEmitter.js:189:10 in emit
文件选择器输出结果
Object { "name": "sinhala-nisadas-10.jpg", "size": 19346, "type": "success", "uri": "/data/user/0/host.exp.exponent/cache/ExperienceData/%40shehan82%2FschoolyMobNative/DocumentPicker/97a75d14-1b7f-468b-aeae-59a6e65aa96b.jpg", }
xhr.onerror捕获的错误信息
Event { "isTrusted": false, }
相关截图



问题原因与解决方案
原因
你拿到的文件uri是Expo沙盒的本地绝对路径,缺少file://协议头,XMLHttpRequest无法识别该类无协议的本地路径,触发请求失败错误。
解决方案
核心修复:补全本地文件uri协议头
在使用uri前判断是否已经带有file://前缀,没有的话主动拼接,修改后的上传函数如下:
const uploadLessonSlide = async (uri) => { // 补全本地文件协议头,避免重复拼接 const fileUri = uri.startsWith('file://') ? uri : `file://${uri}` const blob = await new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.onload = function () { resolve(xhr.response); }; xhr.onerror = function (e) { console.log("error"); console.log(e); reject(new TypeError("Network request failed")); }; xhr.responseType = "blob"; xhr.open("GET", fileUri, true); xhr.send(null); }); // 建议给存储文件添加唯一命名,避免重名覆盖 const ref = storage.ref().child(`images/${Date.now()}_${fileName}`); const snapshot = await ref.put(blob); blob.close(); return await snapshot.ref.getDownloadURL(); };
额外优化
- 上传逻辑外层添加try/catch捕获异常,避免出现未处理的Promise rejection警告
- 若无需兼容旧版本逻辑,可以用fetch API替代XHR,写法更简洁:
const uploadLessonSlide = async (uri) => { const fileUri = uri.startsWith('file://') ? uri : `file://${uri}` const blob = await fetch(fileUri).then(res => res.blob()) const ref = storage.ref().child(`images/${Date.now()}_${fileName}`); const snapshot = await ref.put(blob); blob.close(); return await snapshot.ref.getDownloadURL(); }
内容的提问来源于stack exchange,提问作者Shehan Sandeepa
相关产品推荐
相关产品推荐

