typescript Angular 6:为'root'提供HTTP_INTERCEPTORS

knpiaxh1  于 2022-12-05  发布在  TypeScript
关注(0)|答案(4)|浏览(101)

从Angular 5(在AppModule中提供服务)到Angular 6(在@Injectable decorator中设置“provideIn”键),我已经将所有服务更改为使用新的“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 {
...
}

和许多其他变体,但似乎不知道如何在不将对象文字直接写入模块的提供程序的情况下使其工作。

lf5gs5x2

lf5gs5x21#

这里有几点需要注意:

1.providedIn: 'root'是一个很好的特性,但它可能不是为您构建的

正如@Leon所提到的,这个特性是为了让服务更容易改变树结构。它并不是要完全取代使用模块的providers: []属性。它主要是为库开发人员提供的一个选项,而不是为应用程序开发人员提供的。

想象一下这样的场景:

您在几个月前创建了一个服务,但现在您的应用不再使用它。您知道它没有使用它,因为它是您的应用,并且您对代码库拥有完全的知识和控制权。您对该服务做了什么?
A)确保它使用providedIn: 'root',以便Angular可以将它从捆绑包中抖出来,因为您不再使用它
B)删除服务。
我猜是B!

想象另一个场景:

您正在使用来自npm软件包的第三方Angular模块。该模块有12种不同的服务,您可以在应用中使用这些服务来充分利用其功能。您的应用不需要所有这些功能,因此您只需将其中的3种服务类型注入到应用组件或服务中。
您如何解决此问题?
A)分叉存储库,这样您就可以删除应用不使用的所有服务,这样您就不必将它们包含在捆绑包中。
B)请项目所有者使用providedIn: 'root'。如果库作者使用providedIn: 'root',那么您不使用的服务不会对您的包大小产生影响,它们可以留在npm包/Angular模块中,供其他团队在需要时使用。
我猜是B!

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

拦截器是一个multi DI令牌服务,这意味着您可以为同一个DI令牌提供多个值。该令牌是HTTP_INTERCEPTORS@Injectable({...})装饰器没有公开API,以便像@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: []数组中提供它们意味着您可以显式地设置调用它们的顺序。

odopli94

odopli942#

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

zlwx9yxi

zlwx9yxi3#

在拦截器中

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

在应用程序模块中

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

“providedIn...告诉Angular根注入器负责创建[service]的示例。以这种方式提供的服务〉会自动提供给整个应用程序使用,不需要在任何模块中列出。”
如果无法在服务的@Injectable装饰器中配置提供程序,则在根AppModule中注册应用程序范围的提供程序,而不是在AppComponent中注册。通常,在NgModule中注册提供程序,而不是在根应用程序组件中注册。
此外,如果服务的范围应限于应用程序的功能或分支,则在该分支/功能的顶级组件上提供该服务
https://angular.io/guide/dependency-injection-in-action

xghobddn

xghobddn4#

下面是一个JWT标记拦截器的示例:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http';

@Injectable()
export class JwtInterceptor implements HttpInterceptor {
  intercept(request: HttpRequest<any>, next: HttpHandler) {
    // Get the JWT token from local storage
    const token = localStorage.getItem('jwtToken');

    // If the token exists, add it to the authorization header of the request
    if (token) {
      request = request.clone({
        setHeaders: {
          'x-token': token
        }
      });
    }

    return next.handle(request);
  }
}

若要使用拦截器,您需要在使用它的@NgModule中注册它。在providers数组中,包含拦截器类别,并提供HTTP_INTERCEPTORS词语基元给它。

import { JwtInterceptor } from './jwt.interceptor';

@NgModule({
  // ...
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: JwtInterceptor,
      multi: true
    }
  ]
})
export class AppModule { }

JWT标记拦截器会自动将JWT标记添加到HTTP请求的“x-token”头中,从而允许服务器对请求进行身份验证。

相关问题