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

Ionic 8(Angular 17)中No provider for Storage错误解决求助

Ionic 8(Angular 17)配置Ionic Storage时出现No provider for Storage错误

在Ionic 8(Angular 17)环境中配置Ionic Storage,浏览器控制台抛出错误:

ERROR NullInjectorError: NullInjectorError: No provider for Storage!

我已按照官方文档尝试在独立服务中实现Ionic Storage,相关代码如下:

storage.service.ts

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class StorageService {
  private _storage: Storage | null = null;

  constructor(private storage: Storage) {
    this.init();
  }

  async init() {
    const storage = await this.storage['create']();
    this._storage = storage;
  }

  public async get(key: string) {
    const value = await this._storage?.['get'](key);

    return value;
  }

  public async set(key: string, value: any) {
    await this._storage?.['set'](key, value);
  }
}

auth.service.ts

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { StorageService } from './storage.service';

interface Credentials {
  username: string;
  password: string;
}

export interface AuthResponse {
  auth_token: string;
}

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  constructor(
    private httpClient: HttpClient,
    private storageService: StorageService
  ) {}

  async getAuthToken(): Promise<string> {
    const token = await this.storageService.get('token');

    return token;
  }

  async isAuthenticated(): Promise<boolean> {
    const token = await this.getAuthToken();

    if (token) {
      return true;
    }

    return false;
  }

  authenticate(credentials: Credentials): Observable<AuthResponse> {
    return this.httpClient.post<AuthResponse>(
      `${import.meta.env['NG_APP_API_BASE_URL']}/${
        import.meta.env['NG_APP_API_PREFIX']
      }/token/login`,
      credentials
    );
  }

  async processPostLoginOps(token: string): Promise<void> {
    await this.storageService.set('token', token);

    const authenticated = await this.isAuthenticated();

    if (authenticated) {
      throw new Error('Unable to login');
    }
  }
}

login.page.ts

import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import {
  FormBuilder,
  FormGroup,
  FormsModule,
  ReactiveFormsModule,
  Validators,
} from '@angular/forms';
import { Router } from '@angular/router';
import {
  IonButton,
  IonCard,
  IonCardContent,
  IonCol,
  IonContent,
  IonGrid,
  IonHeader,
  IonInput,
  IonItem,
  IonList,
  IonNav,
  IonRow,
  IonTitle,
  IonText,
  IonToolbar,
} from '@ionic/angular/standalone';
import { LoadingController, ToastController } from '@ionic/angular';
import { AuthService, AuthResponse } from 'src/app/services/auth.service';
import { Capacitor } from '@capacitor/core';

@Component({
  selector: 'app-login',
  templateUrl: './login.page.html',
  styleUrls: ['./login.page.scss'],
  standalone: true,
  imports: [
    IonButton,
    IonCard,
    IonCardContent,
    IonCol,
    IonContent,
    IonGrid,
    IonHeader,
    IonInput,
    IonItem,
    IonList,
    IonNav,
    IonRow,
    IonTitle,
    IonText,
    IonToolbar,
    CommonModule,
    FormsModule,
    ReactiveFormsModule
  ],
})
export class LoginPage implements OnInit {
  form!: FormGroup;
  disabled: boolean = true;
  loadingOverlay!: HTMLIonLoadingElement;
  errorToast!: HTMLIonToastElement;

  constructor(
    private router: Router,
    private formBuilder: FormBuilder,
    private loadingController: LoadingController,
    private toastController: ToastController,
    private authService: AuthService
  ) {}

  async ngOnInit(): Promise<void> {
    this.initForm();
    this.subscribeToFormChanges();
    await this.setOrResetLoadingOverlay();
    await this.setToasts();
  }

  private async setToasts() {
    this.errorToast = await this.toastController.create({
      duration: 1500,
      position: 'bottom'
    });
  }

  private async setOrResetLoadingOverlay() {
    this.loadingOverlay = await this.loadingController.create({});
  }

  initForm(): void {
    this.form = this.formBuilder.group({
      username: ['', Validators.required],
      password: ['', Validators.required],
    });
  }

  subscribeToFormChanges(): void {
    this.form.statusChanges.subscribe((status) => {
      if (status === 'VALID') {
        this.disabled = false;
      } else {
        this.disabled = true;
      }
    });
  }

  async authenticate() {
    this.loadingOverlay.message = 'Logging in';
    await this.loadingOverlay.present();

    this.authService
      .authenticate({
        username: this.form.value.username,
        password: this.form.value.password,
      })
      .subscribe({
        next: async (response: AuthResponse) => {
          this.loadingOverlay.dismiss();
          this.loadingOverlay.message = 'fdnfgnfgn';
          this.loadingOverlay.present();

          try {
            this.authService.processPostLoginOps(response.auth_token);

            this.router.navigate(['/']).then(() => window.location.reload());
          } catch (error) {
            await this.setOrResetLoadingOverlay();
            
            this.errorToast.message = 'Unable to login';
            this.errorToast.present();
          }
        },
        error: async (error: any) => {
          this.loadingOverlay.dismiss();
          await this.setOrResetLoadingOverlay();

          this.errorToast.message = 'Unable to login';
          this.errorToast.present();
        },
      });
  }

  register(): void {
    this.router.navigate(['/register']);
  }
}

解决方案

错误核心原因:未在Angular依赖注入系统中注册Storage提供者,导致StorageService无法获取到Storage实例。

1. 确认依赖安装

确保已安装必要包:

npm install @ionic/storage-angular @capacitor/storage

2. 修正StorageService实现

在独立组件架构下,无需依赖注入Storage,直接手动创建实例更简洁:

import { Injectable } from '@angular/core';
import { Storage } from '@ionic/storage-angular';

@Injectable({
  providedIn: 'root',
})
export class StorageService {
  private _storage: Storage | null = null;

  constructor() {
    this.init();
  }

  async init() {
    // 手动初始化Storage实例
    const storage = new Storage({
      name: '__authdb',
      driverOrder: ['indexeddb', 'websql'] // 根据环境选择存储驱动
    });
    this._storage = await storage.create();
  }

  public async get(key: string) {
    return this._storage?.get(key);
  }

  public async set(key: string, value: any) {
    return this._storage?.set(key, value);
  }
}

3. 修复AuthService逻辑错误

processPostLoginOps方法中逻辑颠倒,应在未验证成功时抛出错误:

async processPostLoginOps(token: string): Promise<void> {
  await this.storageService.set('token', token);

  const authenticated = await this.isAuthenticated();

  if (!authenticated) { // 修改为!authenticated
    throw new Error('Unable to login');
  }
}

4. 验证配置

重启应用后,登录成功可在浏览器开发者工具的Application -> IndexedDB中查看是否存储了token,同时控制台不再抛出No provider for Storage错误。


内容的提问来源于stack exchange,提问作者Tirthya Kamal Dasgupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 09:00:58