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 应用程序,重启后一切正常。
我在拦截器中注入延迟加载服务时遇到 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 应用程序,重启后一切正常。