简体   繁体   English

HttpInterceptor->Service->HttpClient 循环依赖

[英]HttpInterceptor->Service->HttpClient Cyclic Dependency

So I have my authentication service, AuthService , that basically has two methods, one that gets a new token from the server, given a username and a password, and one that retrieves the current stored token and refreshes the tokens during the process when necessary.所以我有我的身份验证服务AuthService ,它基本上有两种方法,一种是从服务器获取新令牌,给定用户名和密码,另一种是检索当前存储的令牌并在必要时在过程中刷新令牌。 Both obviously rely on HttpClient .两者显然都依赖于HttpClient That is, AuthService has a dependency on HttpClient .也就是说, AuthService依赖于HttpClient Let's keep that in mind.让我们牢记这一点。

Another "service" is an HttpInterceptor that I want to intercept all outgoing requests other than those made by AuthService to add the Authorization header (it's getting dirty now).另一个“服务”是一个HttpInterceptor ,我想拦截除AuthService添加授权 header 的请求之外的所有传出请求(现在它变脏了)。 And to make up that header, we need a token, which we get from AuthService .为了组成 header,我们需要一个从AuthService获得的令牌。 That is, AuthInterceptor (the name of my interceptor) has a dependency on AuthService .也就是说, AuthInterceptor (我的拦截器的名称)依赖于AuthService And as far as I know, HttpClient has a dependency on all HTTP_INTERCEPTORS .据我所知, HttpClient依赖于所有HTTP_INTERCEPTORS

So the scenario is as follows:所以场景如下: 循环依赖

Any ideas or suggestions on how to break that circle?关于如何打破这个圈子的任何想法或建议? Is there any way to make AuthService 's HttpClient independent of AuthInterceptor ?有什么方法可以使AuthServiceHttpClient独立于AuthInterceptor吗? Or is it a bad idea?或者这是个坏主意? (Another third function will be added to AuthService for logging the user out, whose requests shall be intercepted and have the Authorization header added to them as well) (另外三分之一的 function 将被添加到AuthService用于注销用户,其请求将被拦截并向其添加授权 header)

So far I found a similar issue but the workaround suggested there doesn't solve my problem, now I get infinite recursion during the bootstrapping process before any requests are sent.到目前为止,我发现了一个类似的问题,但建议的解决方法并没有解决我的问题,现在我在发送任何请求之前的引导过程中得到了无限递归。 I've handled the case of login and token refresh requests being intercepted to avoid this so this is not the issue here as far as I know.我已经处理了登录和令牌刷新请求被拦截的情况以避免这种情况,所以据我所知这不是这里的问题。 Here's a plunk with an overview of my code.这是一个关于我的代码的概述。

Excerpt from the plunk:摘录自 plunk:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private auth: AuthService;

  constructor(inj: Injector) {
    this.auth = inj.get(AuthService);
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // Ignore if login or refresh request
    if (req.url.includes('login')) {
      return next.handle(req);
    }

    console.log('Intercepting request...');
    return this.auth.getToken().map(token => {
      const authHeader = 'Bearer ' + token;
      const authReq = req.clone({setHeaders: {Authorization: authHeader}});
      return authReq;
    }).concatMap(newReq => next.handle(newReq));
  }
}

Try setting this.auth with a timeout:尝试使用超时设置this.auth

constructor(private injector: Injector) {
  setTimeout(() => {
    this.auth = this.injector.get(AuthService);
  })
}

The bug report you have linked to has since been updated, with an alternative workaround (retrieving AuthService in the intercept function / and not setting it in the constructor): https://github.com/angular/angular/issues/18224#issuecomment-316957213您链接到的错误报告已经更新,并提供了替代解决方法(在拦截函数中检索 AuthService/而不是在构造函数中设置它): https : //github.com/angular/angular/issues/18224#issuecomment -316957213

Update 08/02/2018 - angular 5.2.3 2018 年 8 月 2 日更新 - 角度 5.2.3

Just an update on this: this was fixed in angular 5.2.3只是对此的更新:这已在 angular 5.2.3 中修复

https://github.com/angular/angular/blob/master/CHANGELOG.md#bug-fixes-2 https://github.com/angular/angular/blob/master/CHANGELOG.md#bug-fixes-2

So you can directly inject services that depend on HttpClient in HttpInterceptors所以可以直接在HttpInterceptors中注入依赖HttpClient的服务

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

    constructor(private auth: AuthService) 

I was running into the same or a similar issue using Angular 6.1.10.我在使用 Angular 6.1.10 时遇到了相同或类似的问题。 I simply instantiated HttpClient myself inside the service that need to be injected into an HttpInterceptor:我只是在需要注入 HttpInterceptor 的服务中自己实例化了 HttpClient:

@Injectable()
export class AuthService {

  private http: HttpClient;

  constructor(httpBackend: HttpBackend) {
    this.http = new HttpClient(httpBackend);    
  }
}

That broke the infinite loop issue in my case.就我而言,这打破了无限循环问题。

My problem was using the HttpClient in the service constructor that was injected into the HttpInterceptor.我的问题是在注入到 HttpInterceptor 的服务构造函数中使用 HttpClient。

export class SettingsService {
    constructor(
        private http: HttpClient,
    ) {
        this.http.get(...).subscribe() => {
            ...
        });
    }
}

export class AppInterceptor implements HttpInterceptor {
    constructor(
        private settingsS: SettingsService,
    ) { }
    ...
    ...
}

Just ran into this same error.刚遇到同样的错误。 In my case I was injecting a translateService into my interceptor, and my translateService injects DateAdapter into it.在我的例子中,我将一个translateService注入到我的拦截器中,而我的 translateService 将DateAdapter注入到其中。 I was actually missing the module import in order for DateAdapter to work (MatNativeDateModule), and for some reason that missing import in my module was causing the circular dependency.我实际上缺少模块导入以便 DateAdapter 工作 (MatNativeDateModule),并且由于某种原因我的模块中缺少导入导致循环依赖。

Hope this helps someone else, and maybe someone can help me understand why a missing import would cause a circular dependency?希望这对其他人有帮助,也许有人可以帮助我理解为什么缺少导入会导致循环依赖? It doesn't really make sense to me.这对我来说真的没有意义。

UPDATE:更新:

I just figured out why this was happening.我刚刚弄清楚为什么会这样。 Since my interceptor uses my translateService (which is actually just transloco under the hood), and the transloco-root-module ALSO uses HttpClient for the getTranslation function, if that request to get the json file failed for whatever reason then the interceptor would get called.由于我的拦截器使用我的translateService (实际上只是引擎盖下的 transloco),并且 transloco-root-module 还使用 HttpClient 获取getTranslation function,如果获取 json 文件的请求因任何原因失败,那么拦截器将被调用. So what is happening is:所以发生的事情是:

  • transloco depends on HttpClient transloco 依赖于 HttpClient
  • HttpClient depends on HttpInterceptor HttpClient 依赖于 HttpInterceptor
  • HttpInterceptor depends on transloco HttpInterceptor 依赖transloco

循环依赖

This took quite a while for me to debug since it was very rare that loading the transloco json file would fail.我花了很长时间来调试,因为加载 transloco json 文件失败的情况很少见。 But just in case it does happen, I used HttpBackend in my transloco-root-module instead to create a new HttpClient (HttpClients that are created this way do not use any interceptors, so my interceptor will never get called from transloco)但为了以防万一,我在我的 transloco-root-module 中使用了 HttpBackend 而不是创建一个新的 HttpClient(以这种方式创建的 HttpClients 不使用任何拦截器,所以我的拦截器永远不会从 transloco 调用)

export class TranslocoHttpLoader implements TranslocoLoader
{
  private httpClient: HttpClient;

  constructor(httpBackend: HttpBackend)
  {
    this.httpClient = new HttpClient(httpBackend);
  }

  public getTranslation(lang: string)
  {
    return this.httpClient.get<Translation>(`/assets/i18n/${lang}.json`);
  }
}

I don't know if it may help or not, but I got the same issue and I realized that I missed importing the "HttpClientModule" in "app.module.ts"我不知道它是否有帮助,但我遇到了同样的问题,我意识到我错过了在“app.module.ts”中导入“HttpClientModule”

I've just ran into the exact same issue, read the (now closed) thread on Angular github and came up with my own solution;我刚刚遇到了完全相同的问题,阅读了 Angular github 上的(现已关闭)线程并提出了我自己的解决方案; maybe there is something wrong with it which I'm unaware of, but it looks pretty clean to me:也许它有什么我不知道的问题,但它对我来说看起来很干净:

Why not treat your AuthInterceptor as a stateful service?为什么不将您的AuthInterceptor视为有状态服务? You can always just add a method allowing setting the token in the AuthInterceptor and then set it from your AuthService :您始终可以只添加一个允许在AuthInterceptor中设置令牌的方法,然后从您的AuthService中设置它:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    private token: string;
   
    setToken(token: string) {
        this.token = token;
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        ...
    }
}

This way, AuthService requires HttpClient and AuthInterceptor and there is no circular dependency.这样, AuthService需要HttpClientAuthInterceptor并且没有循环依赖。 Just remember to provide the same instance of AuthInterceptor for both HTTP_INTERCEPTORS and AuthInterceptor injection tokens with useExisting :请记住使用AuthInterceptorHTTP_INTERCEPTORSAuthInterceptor注入令牌提供相同的useExisting实例:

providers: [
    AuthInterceptor,
    {
        provide: HTTP_INTERCEPTORS,
        useExisting: AuthInterceptor,
        multi: true
    },

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 HttpInterceptor-&gt;Custom Service-&gt;Module 循环依赖 - HttpInterceptor->Custom Service->Module circular dependency 当我在HttpInterceptor类中注入一个使用HttpClient的服务时,Angular 6进入无限循环依赖循环 - Angular 6 enters infinite loop of cyclic dependency when I inject a service that uses HttpClient inside my HttpInterceptor class 与httpClient的内存Web API循环依赖角度 - Angular in memory web api cyclic dependency with httpClient 无法实例化循环依赖! HttpClient (“[ERROR -&gt;]”): 在 NgModule AppModule 中 ./AppModule@-1:-1 - Cannot instantiate cyclic dependency! HttpClient (“[ERROR ->]”): in NgModule AppModule in ./AppModule@-1:-1 Angular 服务通过相同的接口/抽象类调用服务 =&gt; 循环依赖 - Angular service calls a service by same interface/abstract class => cyclic dependency 从服务调用组件函数-可能的循环依赖关系-Angular - Call a Components function from a Service - possible cyclic dependency - Angular HttpInterceptor中的注入服务未初始化 - Injected Service in HttpInterceptor not initialized Angular 9:注入延迟加载服务时的拦截器循环依赖 - Angular 9: interceptor cyclic dependency while injecting lazy loaded service 无法在拦截器使用的服务内实例化循环依赖 - Cannot instantiate cyclic dependency inside a service used by an interceptor 获取循环依赖项错误 - Getting a cyclic dependency error
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM