【问题标题】:HttpInterceptor->Custom Service->Module circular dependencyHttpInterceptor->自定义服务->模块循环依赖
【发布时间】:2020-11-18 17:06:07
【问题描述】:

在我的 Angular 10 应用程序中,我的核心模块包含以下 2 个服务:

1.HttpResponseInterceptor - 拦截 http 响应,如果它的状态是 401 则重定向到某个登录页面。

@Injectable()
export class HttpResponseInterceptor implements HttpInterceptor {
  constructor(private configService: ConfigService) {
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(catchError(error => {
      if (!!error.status && error.status === 401) {
        window.location.href = this.configService.getLoginPage();
        return NEVER;
      }
      return throwError(error);
    }));
  }

2.ConfigService - 负责从文件系统加载配置文件和一些环境数据

@Injectable({providedIn: CoreModule})
export class ConfigService{
  private readonly CONFIG_URL = 'assets/cfg.json';
  public configuration: Configuration;
  public wasEnvLoaded = false;

  constructor(private httpClient: HttpClient) {
    this.loadConfigurations();
  }

  public loadConfigurations(): any {
    if (!this.configuration) {
      this.httpClient.get<Configuration>(this.CONFIG_URL).subscribe((config: Configuration) => {
          this.configuration = config;
          this.wasEnvLoaded = true;
        }
      );
    }
  }
}

和我的核心模块:

@NgModule({
  imports: [
    HttpClientModule,
  ],
  exports: [],
  providers: [ {provide: HTTP_INTERCEPTORS, useClass: HttpResponseInterceptor, multi : true}],
  declarations: []
})

export class CoreModule {
  constructor(@Optional() @SkipSelf() parentModule: CoreModule) {
    if (parentModule) {
      throw new Error('CoreModule is already loaded. Import only in AppModule');
    }
  }
}

我实施了here 提供的解决方案,一切正常。但是,我仍然在服务和核心模块之间收到循环依赖警告。谁能解释一下为什么?

export class HttpResponseInterceptor implements HttpInterceptor {
  private loginPage: string;
  private configurationLoaderService: ConfigurationLoaderService;

  constructor(private injector: Injector) {
    setTimeout(() => {
      this.configurationLoaderService = this.injector.get(ConfigurationLoaderService);
      this.loginPage = this.configurationLoaderService.configuration.cognitoLoginURL;
    });
  } 

intercept(...){

错误:

循环错误:错误错误:无法实例化循环依赖!配置服务

【问题讨论】:

    标签: angular


    【解决方案1】:

    {providedIn: CoreModule} 如果只注入到您的根模块中,它就毫无用处。只需使用{ providedIn: 'root' },那就更好了。这将解决您的循环依赖。另一种方法是将 ConfigService 添加到模块的 providers 数组中,并从服务中删除 providedIn 对象

    您的主要问题是ConfigService 使用HttpClient,但ConfigService 也用于HttpResponseInterceptor,它是从HttpClient 调用的。所以有你的循环依赖。 HttpClient 需要 ConfigService,反之亦然。

    您应该将功能拆分为两个单独的类。不知道你的整个代码,我可以给你这个:

    @Injectable({
      providedIn: 'root'
    })
    export class ConfigDataService {
      private config?: Configuration; 
     
      getLoginPage(): string {
        return this.config?.loginPage;
      }
    
      setConfiguration(config: Configuration): {
        this.config = config;
      } 
    }
    
    @Injectable({
      providedIn: 'root'
    })
    export class ConfigService{
      private readonly CONFIG_URL = 'assets/cfg.json';
      public wasEnvLoaded = false;
    
      constructor(private httpClient: HttpClient, private cd: ConfigDataService) {
        this.loadConfigurations();
      }
    
      public loadConfigurations(): any {
        if (!this.configuration) {
          this.httpClient.get<Configuration>(this.CONFIG_URL).subscribe((config: Configuration) => {
              this.cd.setConfiguration(config)
              this.wasEnvLoaded = true;
            }
          );
        }
      }
    }
    
    @Injectable()
    export class HttpResponseInterceptor implements HttpInterceptor {
      constructor(private cd: ConfigDataService) {
      }
    
      intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(request).pipe(catchError(error => {
          if (!!error.status && error.status === 401) {
            window.location.href = this.cd.getLoginPage();
            return NEVER;
          }
          return throwError(error);
        }));
      }
    

    【讨论】:

    • CoreModule 不是我的根模块。
    • 您建议将我的 configService 中的 {providedIn: CoreModule} 替换为 {providedIn: 'root' } 虽然它没有在 root 中提供。你能解释一下为什么吗?我没有关注
    • 我试图将 ConfigService 添加到我的 CoreModule 中的 providers 数组中 + 在拦截器的构造函数中注入 configService 但我仍然得到循环错误:错误错误:无法实例化循环依赖!配置服务
    • @JeyJ 据我了解,CoreModule 只导入一次,并且是您的根/核心模块/服务的一部分。通过设置providedIn: 'root',你告诉 Angular 这个特定的类应该只被实例化一次,因此将作为一个单例,我认为这是你想要的行为。据我所知,将providedIn设置为某个模块的可能性主要由lib制造商使用
    • 我在 ConfigService 中将 providedIn 更改为“root”。它没有帮助..不确定它是否相关,但我的应用程序组件(根模块)在其构造函数中注入了 ConfigService:export class AppComponent { constructor(private configurationService: ConfigurationService) { }
    猜你喜欢
    • 2017-12-26
    • 2014-04-28
    • 2018-03-17
    • 2017-10-27
    • 2021-09-18
    • 2014-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多