【问题标题】:Angular 6 - Getting download URL for Firebase Storage file after uploadingAngular 6 - 上传后获取 Firebase 存储文件的下载 URL
【发布时间】:2018-12-28 00:52:01
【问题描述】:

我在这里想要完成的是一个简单的想法。

  1. 将文件上传到 Firebase 存储

  2. 获取文件的链接并将其插入表单中。

问题是,我无法获取下载地址。

当我上传某些内容时,它确实会上传,但我收到以下错误消息:

Object { code_: "storage/object-not-found", message_: "Firebase Storage: Object 'rnmgm3vvpz' does not exist.", serverResponse_: "{\n  \"error\": {\n    \"code\": 404,\n    \"message\": \"Not Found.  Could not get object\"\n  }\n}", name_: "FirebaseError" }

这是要上传到component.ts的代码:

upload(event) {
  const id = Math.random().toString(36).substring(2);
  this.ref = this.afStorage.ref(id);
  this.task = this.ref.put(event.target.files[0]);
  this.uploadState = this.task.snapshotChanges().pipe(map(s => s.state));
  this.uploadProgress = this.task.percentageChanges();
  this.downloadURL = this.ref.getDownloadURL();
}

在component.html上:

<input type="file" (change)="upload($event)" accept=".png,.jpg" />

文件上传后如何获取downloadURL?

【问题讨论】:

  • 试试这个答案在这个时间点是如何工作的https://stackoverflow.com/a/57267424/11127383
  • 找不到对象,因为应该在文件完成加载后进行 downloadURL 调用。如@dAxx_所述,将其从uploadEvent 函数中删除并添加到finalize 函数中

标签: angular firebase google-cloud-firestore


【解决方案1】:

您应该在管道中添加一个 finalize(),例如:

this.task.snapshotChanges().pipe(
  finalize(() => {
    this.downloadURL = this.ref.getDownloadURL(); // <-- Here the downloadURL is available.
  })
).subscribe();

在 finalize() 步骤中,downloadURL 可用,因此您可以从 ref 中异步获取他。 --更新
您说您使用的是 Angular 6,所以我假设您使用的是最新版本的 firebase。
他们将 getDownloadURL() 从 Task 更改为 Observable,因此要获取实际 URL,您只需订阅即可。

this.task.snapshotChanges().pipe(
  finalize(() => {
    this.ref.getDownloadURL().subscribe(url => {
      console.log(url); // <-- do what ever you want with the url..
    });
  })
).subscribe();

【讨论】:

  • StorageReference.getDownloadUrl() 返回 Task 而不是实际的 URL。您可能想要更新您的答案,以展示如何向任务添加完成侦听器并从中获取实际 URL。
  • @FrankvanPuffelen 正是我得到的。这是一个很好的答案,但它没有给我下载 URL。
  • @Rosenberg,如果您使用的是最新的 firebase,getDownloadURL() 不是任务,而是 Observable。我编辑我的帖子以获得答案。祝你好运..
  • 啊...您正在使用 AngularFire。它确实是一个可观察的,它也巧妙地摆脱/封装了异步行为。
【解决方案2】:

ref.getDownloadURL() 必须在 task.snapshotChanges() 完成后调用。

选项1:可以使用concat和defer执行ref.getDownloadURL()

concat(
  this.task.snapshotChanges().pipe(ignoreElements()) // ignore snapshot changes
  defer(() => this.ref.getDownloadURL()) // execute getDownloadURL when snapshot changes completed
).subscribe(url => console.log(url));

选项 2: 在task.snapshotChanges() 完成后,switchMap 到 ref.getDownloadURL()。

this.task.snapshotChanges().pipe(
  last(),  // emit the last element after task.snapshotChanges() completed
  switchMap(() => this.ref.getDownloadURL())
).subscribe(url => console.log(url))

【讨论】:

    【解决方案3】:
    this.angularFireStorage.upload("path_name", file).then(rst => {
            rst.ref.getDownloadURL().then(url => {
              console.log(url);
            })
          })
    

    这就是答案。不想打两次电话。我的包版本是

    "@angular/fire": "^5.1.2", “火力基地”:“^5.9.1”

    【讨论】:

      【解决方案4】:

      @dAxx_ 答案的开头是正确的,但是嵌套订阅是非常糟糕的做法。

      查看这个 StackOverflow 答案Is it good way to call subscribe inside subscribe?

      现在,AngularFire docs 已经很清楚了,除了可能在以下示例中使用 getDownloadURL 管道

      @Component({
       selector: 'app-root',
       template: `<img [src]="'users/davideast.jpg' | getDownloadURL" />`
       })
       export class AppComponent {}
      

      他们可能会提到您需要在相关模块中进行以下导入

      import { GetDownloadURLPipeModule } from '@angular/fire/compat/storage';
      
      ...
      
      imports: [
        GetDownloadURLPipeModule
       ],...
      

      但是,如果您可能不需要下载 URL,那么简单的答案。

      我不确定其背后的原因是什么,但 Firebase 团队已经为我们提供了足够的方式来显示上传的图片,而无需关心下载 URL 字符串。

      首先,getDownloadURL 是一个 Observable,因此您可以像这样显示您的图像

      ...
      finalize(() => {
            this.downloadURL = this.ref.getDownloadURL()
      ...
      
      
      <img *ngIf="downloadURL | async as imgUrl"  [src]="imgUrl" alt="">
      

      或者,您可以使用我上面提到的第一个解决方案,使用文件路径和 getDownloadURL 管道

      最后,您可以使用 Angular Fire 文档中的以下示例

         @Component({
         selector: 'app-root',
          template: `<img [src]="profileUrl | async" />`
          })
         export class AppComponent {
           
           profileUrl: Observable<string | null>;
           constructor(private storage: AngularFireStorage) {
             const ref = this.storage.ref('users/davideast.jpg');
             this.profileUrl = ref.getDownloadURL();
          }
         }
      

      在这种情况下,您只需要关心文件路径,例如,如果您需要在数据库中保存对上传图像的引用。

      【讨论】:

        【解决方案5】:

        试试这个,对我有用

        task.snapshotChanges()
            .pipe(
                  finalize(() => {
                    this.downloadURL = fileRef.getDownloadURL();
                    this.downloadURL.subscribe(downloadURLResponse => {
                       console.log('downloadURL', downloadURLResponse);
                    });
                  }),
             )
            .subscribe();
        

        【讨论】:

          【解决方案6】:

          这是一个包含所有导入的完整方法。

          import { AngularFireStorage, AngularFireStorageReference, AngularFireUploadTask } from '@angular/fire/storage';
          import {finalize} from 'rxjs/operators';
          
          constructor(private afStorage:AngularFireStorage) { }
          
          yourfile:File;
          
          onsubmit(){
          const id = Math.random().toString(36).substring(2);
          const fileRef:AngularFireStorageReference=this.afStorage.ref("YourDir").child(id);
          const task: AngularFireUploadTask =fileRef.put(this.yourfile);
          task.snapshotChanges().pipe(
              finalize(() => {
                  fileRef.getDownloadURL().subscribe(downloadURL => {
                    this.profileurl=downloadURL;
                      console.log(downloadURL);
                  });
            })
          ).subscribe();
          }
          

          【讨论】:

            猜你喜欢
            • 2017-07-08
            • 2021-08-22
            • 1970-01-01
            • 2018-12-08
            • 2018-12-30
            • 2018-01-24
            • 1970-01-01
            • 2018-11-07
            相关资源
            最近更新 更多