注入服务时Angular 5 Http Interceptors错误

时间:2018-01-17 05:31:49

标签: angular dependency-injection angular-http-interceptors

在角度5 +中使用自定义HttpInterceptors时,我收到以下奇怪的依赖注入行为。

以下简化代码可以正常工作:

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

        intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
            const token = this.auth.getToken();
            return next.handle(req);
        }
    }
    export class AuthService {
        token: string;
        constructor() {
          console.log('AuthService.constructor');
        }
    }

...无论其

AuthService本身有1个或多个依赖项时,例如

   export class AuthService {
      token: string;
      constructor(private api: APIService) {
         console.log('AuthService.constructor');
      }
   }

angular尝试重复创建AuthService的新实例,直到收到以下错误:

日志显示AuthService.constructor消息~400次

  

Cannot instantiate cyclic dependency! HTTP_INTERCEPTORS ("[ERROR ->]"): in NgModule AppModule

  

app.component.html:44 ERROR RangeError:最大调用堆栈大小   超过

然后我尝试使用Injector类注入服务 -

 export class AuthService {
      token: string;
      api: APIService;
      constructor(private injector: Injector) {
         this.api = this.injector.get(APIService);
         console.log('AuthService.constructor');
      }
   }

但得到相同的错误(最大调用堆栈大小)。

APIService是一个简单的服务,只在其构造函数中注入HttpClient

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

最后,当我使用AuthServiceInjector注入Interceptor时,错误消失但AuthService被实例化200次以上:

export class AuthInterceptor implements HttpInterceptor {
    auth: AuthService;
    constructor(private injector: Injector) {}
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
           this.auth = this.auth || this.injector.get(AuthService);
           const token = this.auth.getToken();
           return next.handle(req);
        }
    }

查看官方文档和其他示例,似乎技术上可以将服务注入Http拦截器。是否有任何限制或任何其他设置可能会丢失?

8 个答案:

答案 0 :(得分:9)

2018年1月底更新

Angular Team在2018年1月31日发布的Angular 5.2.3中解决了这个问题。更新角度版本后,您将能够在构造函数中正常注入使用HTTPClient的服务

  

错误修复

     

常见:允许HttpInterceptors注入HttpClient(#19809)(ed2b717),关闭#18224

from Angular changelog

答案 1 :(得分:5)

事实证明,如果注入Http Interceptor的服务依赖于HttpClient,则会导致循环依赖。

由于我的AuthService混合了所有不同的逻辑(登录/退出,路由用户,保存/加载令牌,进行api调用),我将拦截器所需的部分分离为自己的服务(只是用户凭证和令牌),现在将其成功注入拦截器。

export class AuthInterceptor implements HttpInterceptor {
    constructor(private credentials: CredentialsService) {}
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const token = this.credentials.getToken();
        const api_key = this.credentials.getApiKey();
    }
}

export class CredentialsService {
    token: string;
    user: IUser;
    constructor(private http: HttpClient) {
        this.loadCredentialsFromStorage();
    }
}

这似乎工作正常。希望这有助于某人。

答案 2 :(得分:3)

您需要将Injector添加到构造函数中,并通过注入器

注入AuthService
export class AuthInterceptor implements HttpInterceptor {
            constructor(private inj: Injector) {}

            intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
                const auth = this.inj.get(AuthService);
                const token = this.auth.getToken();
                return next.handle(req);
            }
        }

不要忘记导入

import {Injector} from '@angular/core';

答案 3 :(得分:2)

对我来说,@ Benjineer answar帮助在app.module.ts中提供了所需的服务。

尽管是相互干扰的,但在app.module.ts中添加为依赖项的顺序是在服务的构造函数中获取的。

例如:在应用模块中,您按照AuthService,ErroMsgService的顺序提供

deps: [AuthService, ErrorMsgService]

在HttpInterceptor构造函数中,您必须以相同的顺序创建它们

 constructor(
    private authService: AuthService,
    private errorService: ErrorMsgService
    ) {}

答案 4 :(得分:1)

我遇到了与拦截器相同的auth服务设计的类似问题。

@Injectable() AuthInterceptorService {
    constructor (authApi: AuthApiService) {}
    handle () {...do the job}
}

@Injectable() AuthApiService {
   constructor () {
       // ...do some setup with a request, such as to get current session
       // that leads to an indirect circular between 2 constructors. 
   }

}

在我的情况下,我发现原因是我尝试在auth服务的构造函数中启动http请求。此时,注入器似乎还没有完成auth服务实例的注册,而http客户端捕获新请求并尝试再次实例化拦截器,因为前一个拦截器实例被卡在其构造函数中在电话堆栈上也是!

使用两个构造函数进行递归调用,会破坏注入器的单例模式并导致调用堆栈外。

答案 5 :(得分:1)

您需要将auth服务添加为拦截器的依赖项。

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

答案 6 :(得分:0)

对于此问题,请确保需要将在Http拦截器中注入的服务与模块中的HTTP_INTERCEPTORS一起添加到提供程序中。

Data$unique_vals <- lapply(Data$Y, unique)
Data$count <- lengths(Data$Y)

答案 7 :(得分:0)

如果以防万一,服务类在Injector类的同一文件中声明,则应首先声明和定义服务类。接下来是Injector类,其中服务类作为依赖项注入。

按照上述结构确实可以解决我的问题。