Angular9: 注入延迟加载服务时拦截循环依赖

Angular 9: interceptor cyclic dependency while injecting lazy loaded service

我在拦截器中注入延迟加载服务时遇到 Cannot instantiate cyclic dependency! InjectionToken HTTP_INTERCEPTORS 错误。

但是,很奇怪我的问题正在通过向拦截器中的服务注入添加一个空 setTimeout(() 来解决。我想知道为什么会这样...

延迟加载LanguageService:

import { HttpClient } from '@angular/common/http';
@Injectable()

export class LanguageService {

  constructor(private http: HttpClient,
    private _translate: TranslateService) {
    this.getLanguages();
  }
// ....

拦截器:

import { Injectable, Injector } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http';
import { LanguageService } from '../app/blog/services/language.service';

@Injectable()

export class LanguageInterceptor implements HttpInterceptor {
    private _languageService:LanguageService;

    constructor(private injector: Injector) {
        /*  This way Works!
            setTimeout(() => {
            this._languageService = this.injector.get(LanguageService)
         })*/

      
            this._languageService = this.injector.get(LanguageService)
         
    }
    
    intercept(req: HttpRequest<any>, next: HttpHandler) {
    

拦截器桶:

import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { LanguageInterceptor } from './lang-interceptor';

export const httpInterceptorProviders = [
  { provide: HTTP_INTERCEPTORS, useClass: LanguageInterceptor, multi: true }
];

共享模块

import { NgModule } from '@angular/core';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { HttpClient, HttpClientModule, HttpClientJsonpModule } from '@angular/common/http';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { httpInterceptorProviders } from 'src/utilities/interceptor-barrel';
import { ShareModule } from '@ngx-share/core';
import { FormsModule, ReactiveFormsModule }   from '@angular/forms';

export function HttpLoaderFactory(http: HttpClient) {
    return new TranslateHttpLoader(http, '../assets/i18n/', '.json');
}

const MODULES = [
    HttpClientModule,
    HttpClientJsonpModule,
    CommonModule,
    RouterModule,
    ShareModule,
    FormsModule,
    ReactiveFormsModule
];

@NgModule({
    imports: [
        MODULES,
        TranslateModule.forRoot({
            defaultLanguage: 'en',
            loader: {
                provide: TranslateLoader,
                useFactory: (HttpLoaderFactory),
                deps: [HttpClient]
            }
        }),
    ],
    exports: [
        MODULES,
        TranslateModule
    ],
    declarations: [],
    providers: [
        httpInterceptorProviders
    ],
})

延迟加载模块:

 // ....
imports: [
        SharedModule
    ]
 // ....
 providers: [
        LanguageService
    ]

问题出在您包含拦截器的位置。您的拦截器应该是您的 app/core 模块的一部分。

您的 LanguageService 不应添加到延迟加载模块的提供程序中。它不应添加到模块的任何 providers 数组中。它应该在装饰器中有一个providedIn: 'root'

@Injectable({ providedIn: 'root' })
export class LanguageService {}

//  lazy loaded module
imports: [
  SharedModule
]

// ....
providers: []

另一方面,拦截器应该在您的核心模块中声明,该模块包含在应用程序根目录中一次。或者在延迟加载模块中,为该延迟加载模块定义一个拦截器


您应该重组您的申请。将您的 SharedModule 拆分为 - 仅 - (!重要)包括 components/pipes/directives。这些是应该放在 SharedModule 中的东西。什么 - 绝对 - 不应该放在那里,是与应用程序相关的服务和进口。

从外观上看,您的 SharedModule 应该是一个 CoreModule,并且只能在您的 AppModule 中导入(而不是导出)。你不应该在延迟加载的模块中导入这个模块。在你的情况下,它将重新声明 HttpClientModule - 没有 - 拦截器,因为它们是在根目录而不是在惰性模块中声明的,使你遇到了你面临的问题。

Angular本身有一个good overview有哪些模块,应该包含哪些不应该包含,哪些应该导入哪些不应该导入:

There are five general categories of feature modules which tend to fall into the following groups:

  • Domain feature modules.
  • Routed feature modules.
  • Routing modules.
  • Service feature modules.
  • Widget feature modules.

我遇到了同样的问题,但我终于发现我应该重启 angular 应用程序,重启后一切正常。