Angular中Firebase下载URL无法写入Firestore,如何修复?
问题:Firebase存储文件上传成功但下载URL无法写入Firestore
代码片段
Firebase服务文件
export class FirebaseService { constructor(private afs: AngularFirestore, private storage: AngularFireStorage) {} uploadFile(file: any) { const filePath = 'path/to/save/file'; const fileRef = this.storage.ref(filePath); const task = this.storage.upload(filePath, file); return task.snapshotChanges().pipe( finalize(() => { return fileRef.getDownloadURL() }) ).toPromise(); } createDocument(collection: string, name: string, file: any) { this.uploadFile(file).then(downloadURL => { if (downloadURL) { const data = { title: name, downloadURL: downloadURL }; this.afs.collection(collection).add(data); } else { console.log("downloadURL is not defined."); } }); } }
组件代码
export class CreatePage implements OnInit { name = "" file: any; onFileChanged(event: any) { this.file = event.target.files[0]; } onSubmit() { console.log("this.selectedOption = ",JSON.stringify(this.selectedOption)) console.log("this.name = ",JSON.stringify(this.name,)) console.log("this.file = ",JSON.stringify(this.file)) console.log("TEST", this.file) this.firebaseService.createDocument(this.selectedOption, this.name, this.file) this.name = "", this.selectedOption = "" } }
HTML代码
<ion-item> <input type="file" (change)="onFileChanged($event)"> </ion-item>
控制台输出
Selected option: freunde this.selectedOption = "freunde" this.name = "test" this.file = {} TEST File {name: 'berge.jpg', lastModified: 1673618629595, lastModifiedDate: Fri Jan 13 2023 15:03:49 GMT+0100 (Mitteleuropäische Normalzeit), webkitRelativePath: '', size: 990092, …} Selected option:
错误信息
core.mjs:9095 ERROR Error: Uncaught (in promise): FirebaseError: [code=invalid-argument]: Function addDoc() called with invalid data. Unsupported field value: undefined (found in field downloadURL.metadata.cacheControl in document freunde/lcAwFcHvQSo5iV6ExQPi)
打印的data对象
data = { "title": "test", "downloadURL": { "source": { "source": { "source": {} } } } }
解决方案
问题根源在于uploadFile方法:finalize中返回的fileRef.getDownloadURL()是一个Observable对象,而非实际的URL字符串。转成Promise后得到的是Observable的订阅结构,导致写入Firestore时出现数据格式错误。
修改uploadFile方法(方案一:使用switchMap)
import { switchMap } from 'rxjs/operators'; uploadFile(file: any) { const filePath = 'path/to/save/file'; const fileRef = this.storage.ref(filePath); const task = this.storage.upload(filePath, file); return task.snapshotChanges().pipe( finalize(() => {}), // 切换到获取下载URL的Observable switchMap(() => fileRef.getDownloadURL()) ).toPromise(); }
修改uploadFile方法(方案二:使用lastValueFrom,RxJS 7+推荐)
import { lastValueFrom } from 'rxjs'; uploadFile(file: any) { const filePath = 'path/to/save/file'; const fileRef = this.storage.ref(filePath); const task = this.storage.upload(filePath, file); // 监听上传进度(可选) task.snapshotChanges().pipe(finalize(() => {})).subscribe(); // 转换下载URL的Observable为Promise return lastValueFrom(fileRef.getDownloadURL()); }
优化createDocument的错误处理
为避免未捕获异常,建议添加错误捕获逻辑:
createDocument(collection: string, name: string, file: any) { this.uploadFile(file) .then(downloadURL => { if (downloadURL) { const data = { title: name, downloadURL: downloadURL }; return this.afs.collection(collection).add(data); } else { console.log("downloadURL is not defined."); } }) .catch(error => { console.error("上传或写入Firestore失败:", error); }); }
修改后,uploadFile返回的Promise会解析为实际的下载URL字符串,写入Firestore时即可正常存储。
内容的提问来源于stack exchange,提问作者Mark Baumann
相关产品推荐
相关产品推荐

