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

特性模块中Injection Token注入失败:StaticInjectorError无提供者求助

嘿,我之前也踩过类似的坑,这大概率是Angular注入器层级和NgRx Effects的注入上下文导致的问题,咱们一步步拆解解决:

问题根源分析

Angular的注入器是分层的,而NgRx Effects默认会使用根注入器实例化。当你在惰性加载的特性模块中单独提供REST_ENDPOINTS Token时,这个Token只存在于特性模块的子注入器中;如果你的Feature Effects还是由根注入器创建,自然找不到特性模块里的提供者,就会抛出StaticInjectorError。

另外还要排除一个基础问题:你有没有在多个地方重复定义REST_ENDPOINTS Token?如果特性模块自己又创建了一个同名Token,那和根模块的Token根本不是同一个,注入肯定失败。

分步解决方案

1. 确保Token全局唯一且正确导出

先检查你的Token定义文件,必须是在共享位置导出,全局和特性模块都引用同一个Token:

// 比如在shared/tokens/rest-endpoints.token.ts
import { InjectionToken } from '@angular/core';

export const REST_ENDPOINTS = new InjectionToken<Record<string, string>>('REST_ENDPOINTS');

绝对不要在特性模块里再重新创建new InjectionToken(...),必须直接导入这个共享的Token。

2. 配置特性模块的Effects和Token提供者

在特性模块中,一定要用EffectsModule.forFeature()来注册当前模块的Effects,这样Angular会用特性模块的子注入器来实例化这些Effects,就能拿到模块内提供的Token了:

// feature/feature.module.ts
import { NgModule } from '@angular/core';
import { EffectsModule } from '@ngrx/effects';
import { REST_ENDPOINTS } from '../../shared/tokens/rest-endpoints.token';
import { FeatureEffects } from './feature.effects';

@NgModule({
  imports: [
    // 关键:用forFeature注册特性模块的Effects
    EffectsModule.forFeature([FeatureEffects])
  ],
  providers: [
    {
      provide: REST_ENDPOINTS,
      useValue: {
        // 特性模块专属的端点配置
        featureUserApi: '/api/feature/users',
        featureOrderApi: '/api/feature/orders'
      }
    }
  ]
})
export class FeatureModule {}

3. 确保Effects中正确注入Token

在FeatureEffects里,别漏了@Inject()装饰器(因为Token是自定义的,不是类):

// feature/feature.effects.ts
import { Injectable, Inject } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { REST_ENDPOINTS } from '../../shared/tokens/rest-endpoints.token';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';

@Injectable()
export class FeatureEffects {
  loadFeatureUsers$ = createEffect(() =>
    this.actions$.pipe(
      ofType('[Feature] Load Users'),
      map(() => this.http.get(`${this.endpoints.featureUserApi}`))
    )
  );

  constructor(
    private actions$: Actions,
    private http: HttpClient,
    // 必须用@Inject指定Token
    @Inject(REST_ENDPOINTS) private endpoints: Record<string, string>
  ) {}
}

额外检查:模块加载方式

如果你的特性模块是惰性加载的,确保路由配置正确(用loadChildren),这样特性模块才会创建独立的子注入器;如果是即时加载的,根注入器会合并所有模块的提供者,这时候如果根模块和特性模块都提供了同一个Token,根模块的配置会覆盖特性模块的——如果这不是你想要的,可能需要考虑用@Optional()或者分模块创建不同的Token。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:31:01