Ionic 3中FireBase Storage downloadURL无法设置正确值的问题
解决Firebase Storage上传后无法正确获取Download URL的问题
看你代码没贴完,但根据你描述的场景——上传音频到Firebase Storage后,没法把正确的downloadURL写入数据表,我大概率能猜到是异步操作时序不对或者用了已废弃的API导致的,给你整理几个常见坑和修复方案:
1. 必须等上传完成后再获取Download URL
Firebase的文件上传是异步操作,你绝对不能在上传还没完成的时候就去拿URL,得等上传任务彻底完成后再调用获取方法。给你补全并修正后的代码示例:
private doPost() { const fileName = this.navParams.get('name').replace(/^.*[\/]/, ''); const filePath = 'file://' + this.navParams.get('path'); const fullPath = this.navParams.get('name'); this.file.resolveDirectoryUrl(filePath).then((rootDir) => { this.file.getFile(rootDir, fileName, { create: false }).then((fileEntry) => { // 先拿到文件的Blob对象用于上传 fileEntry.file((file) => { const reader = new FileReader(); reader.onloadend = () => { const blob = new Blob([reader.result], { type: file.type }); // 创建Storage存储路径的引用 const storageRef = firebase.storage().ref(`audio-posts/${fileName}`); // 执行上传任务 const uploadTask = storageRef.put(blob); // 监听上传状态变化 uploadTask.on('state_changed', (snapshot) => { // 可选:处理上传进度,比如显示进度条 const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; console.log(`上传进度:${progress}%`); }, (error) => { // 处理上传失败的情况 console.error('上传出错:', error); }, () => { // 上传完成!在这里获取下载URL uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => { console.log('文件下载链接:', downloadURL); // 现在可以把这个URL写入你的数据表了 this.savePostToDatabase(downloadURL); }); } ); }; reader.readAsArrayBuffer(file); }); }).catch(err => console.error('获取文件失败:', err)); }).catch(err => console.error('解析目录失败:', err)); } // 示例:将帖子信息写入Firebase数据库 private savePostToDatabase(downloadURL: string) { // 假设用Firestore,你也可以换成Realtime Database firebase.firestore().collection('posts').add({ audioUrl: downloadURL, createdAt: firebase.firestore.FieldValue.serverTimestamp(), // 其他帖子字段,比如标题、作者等 }).then(() => { console.log('帖子信息已成功保存'); }).catch(err => console.error('保存帖子失败:', err)); }
2. 别用已废弃的downloadURL属性
很多老教程里会直接从上传快照里取snapshot.downloadURL,但这个API早就被废弃了,必须用getDownloadURL()方法异步获取,这是很多人踩坑的核心原因。
3. 检查Storage的安全规则
如果还是拿不到URL,先去Firebase控制台看看你的Storage规则是否允许读取:
rules_version = '2'; service firebase.storage { match /b/{bucket}/o { match /audio-posts/{allPaths=**} { // 如果你需要登录用户才能访问,就用下面这条 allow read, write: if request.auth != null; // 如果允许公开读取(比如不需要登录就能听音频),改成if true; // allow read, write: if true; } } }
4. 用async/await简化异步代码
多层then嵌套很容易搞混时序,换成async/await会让逻辑清晰很多,也不容易出错:
private async doPost() { try { const fileName = this.navParams.get('name').replace(/^.*[\/]/, ''); const filePath = 'file://' + this.navParams.get('path'); // 解析目录和文件 const rootDir = await this.file.resolveDirectoryUrl(filePath); const fileEntry = await this.file.getFile(rootDir, fileName, { create: false }); // 转换文件为Blob const file = await new Promise((resolve, reject) => { fileEntry.file(resolve, reject); }); const blob = await new Promise((resolve) => { const reader = new FileReader(); reader.onloadend = () => resolve(new Blob([reader.result], { type: file.type })); reader.readAsArrayBuffer(file); }); // 上传到Storage并获取URL const storageRef = firebase.storage().ref(`audio-posts/${fileName}`); const uploadSnapshot = await storageRef.put(blob); const downloadURL = await uploadSnapshot.ref.getDownloadURL(); // 写入数据库 await firebase.firestore().collection('posts').add({ audioUrl: downloadURL, createdAt: firebase.firestore.FieldValue.serverTimestamp() }); console.log('整个流程完成:音频上传+链接保存成功'); } catch (err) { console.error('流程出错:', err); } }
按上面的方式调整后,应该就能正确获取到下载链接并写入数据表了。如果还有问题,先看控制台的错误日志,定位是上传环节还是获取URL环节出的问题。
内容的提问来源于stack exchange,提问作者Umut Gür
相关产品推荐
相关产品推荐

