将TranslateService注入拦截器时的角度循环依赖关系



我在向拦截器中注入依赖项时遇到了问题。我想将TranslateService注入HttpErrorInterceptor,但我得到了一个循环依赖性错误。当我删除TranslateService注入时,一切都正常。

我已经在app.module.ts中声明了拦截器。我的应用程序模块如下所示:

@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
CoreModule,
HttpClientModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient],
},
defaultLanguage: 'pl-pl'
}),
AppRoutingModule,
RouterModule,
FormsModule,
ReactiveFormsModule,
ToastrModule.forRoot()
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: JwtInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: HttpErrorInterceptor,
multi: true,
deps: [TranslateService, ToastrService]
}
],
bootstrap: [AppComponent]
})
export class AppModule { }

在AppModule中,我导入了CoreModule,在那里我有一个包含拦截器的文件夹,我的CoreModul看起来像这样:

@NgModule({
declarations: [],
imports: [
CommonModule
],
providers: [
CookieService,
NoAuthGuard,
AuthGuard
]
})
export class CoreModule { }

我把登录页面放在AuthModule中,它看起来像这样:

@NgModule({
declarations: [LoginComponent, AuthComponent, ForgotPasswordComponent],
imports: [
CommonModule,
AuthRoutingModule,
RouterModule,
SharedModule
],
providers: [
AuthService
]
})
export class AuthModule { }

在Authmodule中,我导入了SharedModule,并在其中导出了TranslateModule。SharedModule看起来是这样的:

@NgModule({
declarations: [],
imports: [
CommonModule,
HttpClientModule,
ReactiveFormsModule
],
exports: [
TranslateModule,
ReactiveFormsModule
]
})
export class SharedModule { }

我找不出为什么我在登录页面上出现循环依赖错误。

我的假设是,我已经将CoreModule导入到AppModule中,在那里我保留了拦截器、保护程序,并且我有SharedModule,它对所有功能模块都是即兴的,我想在那里保留例如通用组件。

Błãd,jaki dostajÉto:

core.js:6162 ERROR Error: NG0200: Circular dependency in DI detected for InjectionToken HTTP_INTERCEPTORS. Find more at https://angular.io/errors/NG0200
at throwCyclicDependencyError (core.js:216)
at R3Injector.hydrate (core.js:11381)
at R3Injector.get (core.js:11205)
at HttpInterceptingHandler.handle (http.js:1978)
at MergeMapSubscriber.project (http.js:1114)
at MergeMapSubscriber._tryNext (mergeMap.js:44)
at MergeMapSubscriber._next (mergeMap.js:34)
at MergeMapSubscriber.next (Subscriber.js:49)
at Observable._subscribe (subscribeToArray.js:3)
at Observable._trySubscribe (Observable.js:42)

问题是TranslateModule的初始化依赖于HttpClient,这意味着HttpClientModule需要首先初始化。这会导致HttpErrorInterceptor的初始化,因为拦截器是用HttpClientModule初始化的。这会导致循环依赖,因为您的拦截器需要TranslateService。您可以通过在HttpErrorInterceptor中注入Injector来解决此问题,然后在需要时直接从Injector请求TranslateService。这样可以防止对初始初始化的循环依赖。

由于您没有为拦截器提供代码,因此这里有一个使用这种方法的示例拦截器。

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
constructor(private readonly injector: Injector) {}
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
try {
const translateService = this.injector.get(TranslateService)
// log using translate service
} catch {
// log without translation translation service is not yet available
}
}
}

您仍然需要处理获取翻译服务失败的情况,因为加载翻译时可能会出现错误。

根据这个GitHub问题,包括我在内的一些人能够通过删除TranslateModule.forRoot()中的defaultLanguage来解决这个问题

我已经实现了我的LanguageModule如下:

@NgModule({
imports: [
HttpClientModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [HttpClient]
},
isolate: true
})
],
providers: [
TranslateService
]
})
export class LanguageModule {
public constructor(translateSvc: TranslateService, http: HttpClient) {
translateSvc.onLangChange
.pipe(
switchMap((currentLang: LangChangeEvent) => zip(
of(currentLang),
http.get(`path/to/i18n/${currentLang.lang}.json`)
))
).subscribe(([currentLang, localizations]) => {
translateSvc.setTranslation(translateSvc.currentLang, localizations, true);
});
translateSvc.use(translateSvc.getDefaultLang());
}

然后在我的CoreModule:中导入

@NgModule({
imports: [
CommonModule,
HttpClientModule,
BrowserAnimationsModule,
LanguageModule,
...
],
exports: [],
declarations: [],
providers: [
...
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
}
]
})
export class CoreModule {
public constructor(@Optional() @SkipSelf() parentModule: CoreModule, private translateSvc: TranslateService) {
this.translateSvc.use(environment.defaultLang)
}
}

您可以使用HttpBackend而不是HttpClient。这样你就不会得到";圆形DI";错误,您将绕过所有的拦截器。

loader: {
provide: TranslateLoader,
useClass: TranslationLoader,
deps: [HttpBackend],
},
type TranslateFile = Record<string, string>;
const httpRequest = new HttpRequest<TranslateFile>(
'GET',
`/assets/${lang}.json?v=${appVersion}`
);
return this._httpHandler.handle(httpRequest).pipe(
filter((httpEvent) => httpEvent instanceof HttpResponse),
map((httpResponse) => (httpResponse as HttpResponse<TranslateFile>).body!)
);

相关内容

  • 没有找到相关文章

最新更新