【问题标题】:Angular 6: provide HTTP_INTERCEPTORS for 'root'Angular 6:为“root”提供 HTTP_INTERCEPTORS
【发布时间】:2018-10-17 01:52:00
【问题描述】:

从在 AppModule 中提供服务的 Angular 5 更改为在 @Injectable 装饰器中设置“provideIn”键的 Angular 6,我已将所有服务更改为使用新的“provideIn”方法。但是,我的拦截器服务例外。

如何为“root”提供 HTTP_INTERCEPTORS 令牌并使用 InterceptorService?

这是我使用 atm 的 Angular 5 方式:

@Injectable()
export class InterceptorService implements HttpInterceptor {
...
}

在 AppModule 中:

providers: [{
  provide: HTTP_INTERCEPTORS,
  useClass: InterceptorService,
  multi: true
}]

但是 Angular 6 的方式是什么?

我尝试过类似的东西

@Injectable({
  provideIn: 'root',
  useValue: HTTP_INTERCEPTORS,
  deps: [forwardRef(() => InterceptorService)]
})
export class InterceptorService implements HttpInterceptor {
...
}

以及许多其他带有 Injectable 的变体,但似乎无法弄清楚如何在不将对象文字直接写入模块提供者的情况下使其工作。

【问题讨论】:

标签: angular typescript service injectable angular6


【解决方案1】:

Angular 6 的 provideIn-property 只是 Angular 5 中行为的一个补充。如果你想提供一些已经存在的 InjectionToken,你仍然必须使用 { provide: ClassA, useClass: ClassB } 语法。

见->https://angular.io/guide/dependency-injection-in-action#external-module-configuration

tl;博士: 您提供 HTTP_INTERCEPTORS 的方式在 Angular 6 中没有改变,也没有“Angular 6”方式。

【讨论】:

  • 这似乎相当不一致,因为他们改变了定义如何提供类的首选方式。
  • @MilošTomšik 整个提供的东西(据我所知)是为了使服务可以摇树。因此,通过在组件中导入 ClassA,Angular 将查看 ClassA 并看到它应该在根目录中提供。但是,如果您必须在其类名之外提供其他内容,则您永远不会引用此文件,并且 Angular 将无法告诉您要提供什么。
  • 此外,开发人员很难跟踪应用程序的哪个部分正在使用哪个类。
  • 这是不准确的:“如果你想提供一个带有 InjectionToken 的东西而不是它的类,你仍然必须使用{provide: ClassA, useClass: ClassB}See this answer
  • @BeetleJuice 我编辑了答案以适用于更一般的范围。但老实说,我无法想象你提到的方法是合理的场景
【解决方案2】:

在拦截器中

@Injectable()
export class InterceptorService implements HttpInterceptor {
...
}

在应用模块中

providers: [{
  provide: HTTP_INTERCEPTORS,
  useClass: InterceptorService,
  multi: true
}]

"providedIn ... 告诉 Angular 根注入器负责 创建 [service] 的实例。以这种方式提供的服务 > 自动提供给整个应用程序并且不需要 列在任何模块中。”

"如果不能在@Injectable 装饰器中配置提供程序 服务,然后在根 AppModule 中注册应用程序范围的提供程序,而不是 在应用组件中。通常,在 NgModule 中注册提供者,而不是 > 在根应用程序组件中。”

此外,如果服务的范围应限于应用程序的某个功能或分支,请在该分支/功能的顶级组件中提供该服务

https://angular.io/guide/dependency-injection-in-action

【讨论】:

    【解决方案3】:

    这里有几点需要注意:

    1。 providedIn: 'root' 是一个不错的功能,但它可能不是为您构建的

    正如@Leon 所提到的,此功能旨在使服务更加可摇晃。它并不意味着完全替换使用模块的providers: [] 属性。这是一个主要针对库开发人员的选项,而不是应用程序开发人员。

    想象一下这个场景:

    您几个月前创建了一项服务,现在您的应用不再使用它。您知道它没有使用它,因为它是您的应用程序,并且您对代码库拥有完整的知识和控制权。你对这项服务做了什么?

    A) 确保它正在使用 providedIn: 'root',以便 Angular 可以将它从捆绑包中摇出,因为你不再使用它了

    B) 删除服务。

    我的猜测是 B!

    想象另一个场景:

    您正在使用来自 npm 包的第 3 方 Angular 模块。该模块有 12 种不同的服务,您可以在应用程序中使用它来利用其功能。您的应用不需要所有这些功能,因此您只需将其中 3 种服务类型注入您的应用组件或服务。

    你如何解决这个问题?

    A) fork 存储库,这样您就可以删除您的应用不使用的所有服务,这样您就不必将它们包含在您的包中。

    B) 请项目所有者使用providedIn: 'root'。如果库作者使用了providedIn: 'root',那么您不使用的服务不会影响您的包大小,并且它们可以保留在 npm 包/Angular 模块中以供其他团队在需要时使用。

    我的猜测是 B!

    2。 providedIn: 'root' 不适用于拦截器

    拦截器是multi DI 令牌服务,这意味着您可以为同一个 DI 令牌提供多个值。该令牌是HTTP_INTERCEPTORS@Injectable({...}) 装饰器没有像 @NgModule({...}) 装饰器那样为不同的令牌提供装饰类型。

    这意味着你不能使用 @Injectable({...}) 装饰器告诉 Angular Anywhere you would normally ask for 'HTTP_INTERCEPTORS' add this service to the set of values to use instead

    您只能在 @NgModule({...}) 装饰器中执行此操作。

    3。提供拦截器取决于顺序

    拦截器是一个管道,它们的提供顺序决定了它们访问请求对象(修改或检查)和响应对象(修改或检查)的顺序。

    虽然某些拦截器可能与顺序无关,但您可能仍希望该顺序具有确定性。

    因此,即使providedIn: 'root' 为拦截器工作,提供它们的顺序也将由 Angular 编译步骤期间类型的解析顺序决定 - 可能不是您想要的。

    而不是在@NgModule({...}) 装饰器中的providers: [] 数组中提供它们意味着您可以显式设置它们将被调用的顺序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-01
      • 1970-01-01
      • 2019-04-23
      • 1970-01-01
      • 2019-02-04
      • 2018-11-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多