14

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

4

3 回答 3

7

这里有几点需要注意:

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

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

想象一下这个场景:

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

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

B) 删除服务。

我的猜测是B!

想象另一个场景:

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

你如何解决这个问题?

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

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

我的猜测是B!

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

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

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

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

3. 提供拦截器依赖于顺序

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

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

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

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

于 2018-08-28T21:13:07.160 回答
4

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

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

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

于 2018-05-07T09:55:37.777 回答
2

在拦截器中

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

在应用模块

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

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

“如果无法在服务的 @Injectable 装饰器中配置提供程序,则在根 AppModule 中注册应用程序范围的提供程序,而不是在 AppComponent 中。通常,在 NgModule 中注册提供程序,而不是 > 在根应用程序组件中。”

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

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

于 2018-05-18T14:45:47.183 回答