Angular 6: 为 'root' 提供 HTTP_INTERCEPTORS

Angular 6: provide HTTP_INTERCEPTORS for 'root'

随着您在 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 的变体,但似乎无法弄清楚如何在不将对象文字直接写入模块提供者的情况下使其工作。

provideIn-属性 of Angular 6 只是对 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"-方式。

在拦截器中

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

在应用程序模块中

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

"providedIn ... tells Angular that the root injector is responsible for creating an instance of the [service]. Services that are provided this way are > automatically made available to the entire application and don't need to be listed in any module."

"If a provider cannot be configured in the @Injectable decorator of the service, then register application-wide providers in the root AppModule, not in the AppComponent. Generally, register providers in the NgModule rather than > in the root application component."

此外,如果服务范围应限于应用程序的某个功能或分支,请在该 branch/feature

的顶级组件中提供该服务

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

这里有几点需要注意:

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

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

想象一下这个场景:

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

A) 确保它正在使用 providedIn: 'root' 以便 Angular 可以将它从 bundle 中移除,因为你不再使用它了

B) 删除服务。

我猜是B!

想象另一个场景:

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

你是如何解决这个问题的?

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

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

我猜是B!

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

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

这意味着您无法使用 @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 编译步骤中类型的解析顺序决定——可能不是您想要的。

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