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

Angular 16集成Firebase 9报错:Service storage is not available

解决Angular Fire中「Error: Service storage is not available」问题

问题背景

使用Angular v16项目,搭配@angular/fire: ^7.6.1和手动安装的firebase: ^9.0.0,已完成Firebase初始化。联系表单提交时,上传附件到Firebase Storage出现错误:

Error: Service storage is not available
at Provider.getImmediate
at getStorage
at ContactUsComponent.onSubmit

执行npm ls @firebase/app发现依赖冲突,项目中同时存在两个版本的Firebase核心包:

  • @angular/fire@7.6.1自带firebase@9.23.0,依赖@firebase/app@0.9.13/0.9.14
  • 手动安装的firebase@9.0.0依赖@firebase/app@0.7.0

问题根源

多个版本的@firebase/app共存导致Firebase模块初始化混乱,Storage服务无法被正确识别和加载。Angular Fire已经内置了兼容版本的Firebase SDK,无需单独安装firebase包。

解决方案

1. 清理冲突依赖

卸载手动安装的firebase包,保留Angular Fire自带的兼容版本:

npm uninstall firebase
npm install

2. 统一Firebase导入来源

确保所有Firebase相关的导入都来自@angular/fire或其细分模块,避免直接从firebase包导入,防止版本混淆。

代码调整建议

组件中依赖注入Storage实例

在contact-us.component.ts中,通过Angular依赖注入获取Storage实例,替代手动调用getApp和getStorage:

import { Component } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Storage } from '@angular/fire/storage';
import { ref, uploadBytesResumable, getDownloadURL } from '@firebase/storage';
import { ContactService } from './contact.service';
import { tap, catchError, throwError } from 'rxjs';

@Component({
  selector: 'app-contact-us',
  templateUrl: './contact-us.component.html',
  styleUrls: ['./contact-us.component.css']
})
export class ContactUsComponent {
  contactForm: FormGroup;
  loading = false;
  messageSuccessMessage = false;
  messageFailureMessage = false;
  emailId: string; // 假设已定义

  constructor(
    private fb: FormBuilder,
    private storage: Storage,
    private contactService: ContactService
  ) {
    this.contactForm = this.fb.group({
      fullName: ['', Validators.required],
      email: ['', [Validators.required, Validators.email]],
      phone: [''],
      subject: ['', Validators.required],
      message: ['', Validators.required],
      attachment: ['']
    });
  }

  onFileChange(event: any) {
    if (event.target.files.length > 0) {
      const file = event.target.files[0];
      if (file.size > 5242880) { // 5MB限制
        alert('文件过大!');
        this.contactForm.get('attachment')?.setErrors({ 'incorrect': true });
      } else {
        this.contactForm.get('attachment')?.setValue(file);
      }
    }
  }

  onSubmit() {
    const value = this.contactForm.value;
    const file = value.attachment;
    const newEmail: Partial<Contact> = {
      fullName: value.fullName,
      email: value.email,
      phone: value.phone,
      subject: value.subject,
      message: value.message,
      attachmentUrl: '',
    };

    if (this.contactForm.valid) {
      this.loading = true;

      // 使用唯一路径存储文件,避免覆盖
      const fileRef = ref(this.storage, `contact-attachments/${Date.now()}-${file.name}`);
      const uploadTask = uploadBytesResumable(fileRef, file);

      uploadTask.then((snapshot) => {
        return getDownloadURL(snapshot.ref);
      }).then((downloadURL) => {
        newEmail.attachmentUrl = downloadURL;

        this.contactService.sendContact(newEmail, this.emailId).pipe(
          tap(() => {
            this.loading = false;
            this.contactForm.reset();
            this.messageSuccessMessage = true;
            setTimeout(() => this.messageSuccessMessage = false, 3000);
          }),
          catchError((error) => {
            this.loading = false;
            this.messageFailureMessage = true;
            setTimeout(() => this.messageFailureMessage = false, 3000);
            return throwError(() => error);
          })
        ).subscribe();
      }).catch((error) => {
        console.error('上传失败:', error);
        this.loading = false;
        this.messageFailureMessage = true;
        setTimeout(() => this.messageFailureMessage = false, 3000);
      });
    } else {
      this.contactForm.markAllAsTouched();
    }
  }
}

interface Contact {
  fullName: string;
  email: string;
  phone?: string;
  subject: string;
  message: string;
  attachmentUrl: string;
}

确认AppModule配置

当前app.module.ts中的Storage配置无需修改,确保provideStorage正确注册即可:

provideStorage(() => getStorage()),

验证

完成上述步骤后,重新启动项目,测试联系表单提交功能,确认Storage服务正常加载,附件能成功上传并获取downloadURL。

内容的提问来源于stack exchange,提问作者Robgit28

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 08:39:55