【问题标题】:Separate HttpClient instances per module in AngularAngular 中每个模块的单独 HttpClient 实例
【发布时间】:2021-05-03 13:51:34
【问题描述】:

在 Angulars HttpInterceptor 参考中,我有 found the following section:

要对整个应用程序使用相同的HttpInterceptors 实例,请仅在您的AppModule 中导入HttpClientModule,并将拦截器添加到根应用程序注入器。如果跨不同模块多次导入HttpClientModule(例如,在延迟加载模块中),每次导入都会创建HttpClientModule 的一个新副本,它会覆盖根模块中提供的拦截器。

太棒了,这正是我需要的。所以我可以在每个模块中导入HttpClientModule,这样我的ApiInterceptor 注入一个基本路径和JWT 令牌不会干扰我在AppTranslationModule 中使用的HttpClient,它会获取一些翻译文件。

所以我有我的AppModule

@NgModule({
  declarations: [AppComponent],
  imports: [AppRoutingModule, AppTranslationModule, CoreModule],
  bootstrap: [AppComponent]
})
export class AppModule {}

... 导入 AppTranslationModuleCoreModule。他们每个人都导入HttpClientModule

AppTranslationModule

@Injectable()
export class TranslationLoader implements TranslocoLoader {
  constructor(private http: HttpClient) {}

  getTranslation(lang: string) {
    return this.http.get<Translation>(`/assets/i18n/${lang}.json`);
  }
}

@NgModule({
  imports: [TranslocoModule, HttpClientModule],
  providers: [
    {
      provide: TRANSLOCO_CONFIG,
      useValue: translocoConfig({
        availableLangs: ['en-US', 'de-CH', 'fr-CH', 'it-CH'],
        defaultLang: 'en-US',
        // Remove this option if your application doesn't support changing language in runtime.
        reRenderOnLangChange: true,
        prodMode: environment.production
      })
    },
    { provide: TRANSLOCO_LOADER, useClass: TranslationLoader }
  ],
  exports: []
})
export class AppTranslationModule {}

CoreModule

@NgModule({
  imports: [BrowserModule, BrowserAnimationsModule, RouterModule, HttpClientModule],
  exports: [DefaultLayoutComponent],
  declarations: [DefaultLayoutComponent],
  providers: [
    { provide: BASE_API_URL, useValue: environment.api },
    { provide: HTTP_INTERCEPTORS, useClass: BaseUrlInterceptor, multi: true }
  ]
})
export class CoreModule {}

不幸的是,CoreModule 中的拦截器 (BaseUrlInterceptor) 仍应用于AppTranslationModule 中的HttpClient。如果我正确理解了上述文档,这不应该发生吗?有什么想法吗?

我正在使用 Angular 11。

【问题讨论】:

  • 也可以将{ provide: HTTP_INTERCEPTORS, useClass: BaseUrlInterceptor, multi: true } 提供给appTracslationModule
  • @GaurangDhorda:如果我不想在 AppTranslationModule 中应用拦截器,我为什么要在那里添加它?
  • 好的。那你的用例是什么?你能简单解释一下吗?
  • 我想要两个不同的 HttpClient 实例,一个有拦截器,另一个没有。
  • stackblitz.com/edit/… 你能看到这个例子和你的例子一样吗?

标签: angular dependency-injection angular-httpclient


【解决方案1】:

我在this blog post 找到了解决方案。如上所述,HttpHandler 需要更改,以创建独立于其他拦截器的 HttpClient 的单独实例:

import { HttpBackend, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { InjectionToken, Injector } from '@angular/core';
import { Observable } from 'rxjs';

export class CustomInterceptHandler implements HttpHandler {
  constructor(private next: HttpHandler, private interceptor: HttpInterceptor) {}

  handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
    return this.interceptor.intercept(req, this.next);
  }
}

export class CustomInterceptorHandler implements HttpHandler {
  private chain: HttpHandler | null = null;

  constructor(private backend: HttpBackend, private injector: Injector, private interceptors: InjectionToken<HttpInterceptor[]>) {}

  handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
    if (this.chain === null) {
      const interceptors = this.injector.get(this.interceptors, []);
      this.chain = interceptors.reduceRight((next, interceptor) => new CustomInterceptHandler(next, interceptor), this.backend);
    }

    return this.chain.handle(req);
  }
}

有了这个HttpClient 可以扩展:

import { HttpBackend, HttpClient, HttpInterceptor } from '@angular/common/http';
import { Injectable, InjectionToken, Injector } from '@angular/core';
import { CoreModule } from '../core.module';
import { CustomInterceptorHandler } from './custom-http.handler';

export const API_HTTP_INTERCEPTORS = new InjectionToken<HttpInterceptor[]>('API_HTTP_INTERCEPTORS');

@Injectable({ providedIn: CoreModule })
export class ApiHttpService extends HttpClient {
  constructor(backend: HttpBackend, injector: Injector) {
    super(new CustomInterceptorHandler(backend, injector, API_HTTP_INTERCEPTORS));
  }
}

最后可以将新的HttpClient 和拦截器一起注入到依赖树中:

@NgModule({
  imports: [BrowserModule, BrowserAnimationsModule, RouterModule, HttpClientModule],
  exports: [DefaultLayoutComponent],
  declarations: [DefaultLayoutComponent],
  providers: [
    ApiHttpService,
    { provide: BASE_API_URL, useValue: environment.api },
    { provide: API_HTTP_INTERCEPTORS, useClass: BaseUrlInterceptor, multi: true },
    { provide: API_HTTP_INTERCEPTORS, useClass: ResponseTransformerInterceptor, multi: true }
  ]
})
export class CoreModule {}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-16
    • 1970-01-01
    • 2020-10-18
    • 1970-01-01
    • 2015-06-20
    • 1970-01-01
    • 2018-07-30
    • 2018-11-28
    相关资源
    最近更新 更多