【问题标题】:Injector Error "Provider parse errors: Cannot instantiate cyclic dependency!"注入器错误“提供程序解析错误:无法实例化循环依赖!”
【发布时间】:2018-01-21 02:26:38
【问题描述】:

我尝试创建一个 HttpInterceptor 来为发生的每个 http 添加一些用于授权的标头。我需要从名为 AuthService 的服务中获取标头。下面是代码:

拦截器:

import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { AuthService } from './auth.service';

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

授权服务:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable()
export class AuthService {
  constructor(private http: HttpClient) { }
}

应用模块:

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

我收到以下错误:

错误:提供程序解析错误: 无法实例化循环依赖! InjectionToken_HTTP_INTERCEPTORS ("[ERROR ->]"):在 NgModule AppModule 中 在 ./AppModule@-1:-1

我已经检查了以前的答案,但我不明白在哪里检测到循环依赖。这里描述了我想要做的事情:https://angular.io/guide/http#setting-new-headers

【问题讨论】:

    标签: angular


    【解决方案1】:

    看看这个GitHub Discussion (Issue #18224)

    作为一种解决方法,您可以手动使用Injector 并在intercept 方法中注入相关服务:https://github.com/angular/angular/issues/18224#issuecomment-316957213

    我解决了简单地没有在构造函数中设置 authService 而是得到 在拦截函数中。

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // Get the auth header from the service.
        const auth = this.inj.get(AuthenticationService);
        const authToken = auth.getAuthorizationToken();
        ...
    }
    

    更新:

    不幸的是,在 Angular 4.3.0 之前,不可能在 intercept 方法中手动使用 Injector:

    ERROR Error: Uncaught (in promise): RangeError: Maximum call stack size exceeded

    所以还有一种使用rxjs的解决方法:

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return Observable.create((observer: any) => {
            setTimeout(() => {
                const authService = this.injector.get(AuthenticationService)
                observer.next(authService.getAuthorizationHeader())
                observer.complete()
            })
        })
            .mergeMap((Authorization: string) => {
                let authReq = req
    
                if (Authorization) {
                    authReq = req.clone({
                        setHeaders: {
                            Authorization
                        }
                    })
                }
    
                return next.handle(authReq)
            })
    }
    

    【讨论】:

    • 完美解决方案,拯救了我的一天。
    • 如果你得到这个:http.interceptor.ts:64 Uncaught TypeError: $.a.create(...).mergeMap is not a function 那意味着你导入了错误的mergeMap import 'rxjs/add/operator/mergeMap';
    • 在 Angular 6 上遇到了同样的问题,并用这里的方法解决了 github.com/angular/angular/issues/18224#issuecomment-329939990
    【解决方案2】:

    从提供者列表中删除 AuthService,因为它已经在拦截器中导入,因此是循环依赖。

    【讨论】:

    • AuthService 在我的应用程序的许多部分中使用,并且我在任何地方都需要相同的实例。有什么选择吗?
    • 我想我解决了这个问题,但它看起来很愚蠢......我将 authService 分成两部分。在一个文件中,我得到了所有变量,而在另一个文件中,我得到了所有 http 请求。这样我只需要我的 Interceptor 上的变量消除循环依赖。这是一种反模式还是我应该保留它?无论如何,感谢您的宝贵时间。
    • @itsUndefined 你是如何将你的服务类分成两个的?是不是像从基础服务类派生的两个单独的类?
    • @KunalS 它看起来不是最好的,但我将其拆分,以便有两个相互独立的服务类。在第一个服务中,我拥有有关身份验证的所有变量,例如令牌、用户名等。在第二个服务中,我只注册可观察对象以访问后端。这样,只有不访问身份验证变量的第二个服务才需要 http 导入和依赖注入。在我的登录组件上,我导入了这两个服务。我从第二个服务发送请求。我收到响应并在第一个服务上设置变量。
    • 这样设置身份验证标头的拦截器只需访问不依赖于 http 导入的第一个服务。问题解决了
    【解决方案3】:

    从 AuthService 中删除以下内容 -

    import { HttpClient } from '@angular/common/http';
    

    原因是 - HttpClient 在内部使用拦截器,而拦截器使用 AuthService 和 AuthService 正在使用 HttpClient。因此它给出了“循环依赖”错误。

    【讨论】:

    • Angular 5.2.3 出来后问题已解决。可以在此处查看修复问题的拉取请求:github.com/angular/angular/pull/19809
    • 同意,我在 5.2.0 版本中遇到了这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-14
    • 1970-01-01
    相关资源
    最近更新 更多