You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 03:01:41