从在 AppModule 中提供服务的 Angular 5 到在 @Injectable 装饰器中设置“provideIn”键的 Angular 6,我已将所有服务更改为使用新的“provideIn”方法。但是,我的拦截器服务除外。
如何为“root”提供 HTTP_INTERCEPTORS token 并使用 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 的变体,但似乎无法弄清楚如何在不将对象文字直接写入模块提供者的情况下使其工作。
最佳答案
这里有几点需要注意:
1。 providedIn: 'root'
是一个很好的功能,但它可能不是为你而构建的
正如@Leon 所提到的,此功能旨在使服务更加可摇树。它并不意味着完全替换使用模块的 providers: []
属性。这是一个主要针对库开发人员而非应用程序开发人员的选项。
想象一下这个场景:
您几个月前创建了一项服务,但现在您的应用不再使用它。您知道它没有使用它,因为它是您的应用程序,并且您对代码库有充分的了解和控制权。您对该服务做了什么?
A) 确保它使用的是 providedIn: 'root'
这样 Angular 就可以将它从 bundle 中 tree shake 出来,因为你不再使用它了
B) 删除服务。
我猜是B!
想象另一个场景:
您正在使用 npm 包中的第 3 方 Angular 模块。该模块有 12 种不同的服务,您可以在您的应用程序中使用它来利用其功能。您的应用不需要所有这些功能,因此您只需将其中 3 种服务类型注入(inject)到您的应用组件或服务中。
你是如何解决这个问题的?
A) fork 存储库,这样您就可以删除您的应用不使用的所有服务,这样您就不必将它们包含在您的包中。
B) 要求项目所有者使用 providedIn: 'root'
。如果库作者使用了 providedIn: 'root'
,您不使用的服务不会影响您的包大小,它们可以保留在 npm 包/Angular 模块中供其他团队使用如果他们需要的话。
我猜是B!
2。 providedIn: 'root'
不适用于拦截器
拦截器是一种多
DI token 服务,这意味着您可以为同一个 DI token 提供多个值。该 token 是 HTTP_INTERCEPTORS
。 @Injectable({...})
装饰器没有像 @NgModule({...})
装饰器那样为不同的标记提供装饰类型的 API
这意味着你不能告诉 Angular 任何你通常要求“HTTP_INTERCEPTORS”的地方将此服务添加到要使用的值集中
使用 @Injectable({... })
装饰器。
您只能在 @NgModule({...})
装饰器中执行此操作。
3。提供拦截器是依赖于顺序的
拦截器是一个管道,提供它们的顺序决定了它们访问请求对象(修改或检查)和响应对象(修改或检查)的顺序。
虽然有些拦截器可能与顺序无关,但您仍然可能希望在该顺序中有一些确定性。
因此,即使 providedIn: 'root'
为拦截器工作,它们提供的顺序将由 Angular 编译步骤中类型的解析顺序决定——可能不是你想要的。
而不是在 @NgModule({...})
装饰器中的 providers: []
数组中提供它们意味着您可以显式设置它们将被调用的顺序中。
关于 Angular 6 : provide HTTP_INTERCEPTORS for 'root' ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50211120/