APP_INITIALIZER和相关令牌解析问题

时间:2019-07-08 05:11:38

标签: angular typescript

我正在使用APP_INITIALIZER从json获取配置,并且工作正常。 早些时候,我将身份验证保护作为应用程序的一部分,它过去一直运行良好。

然后,我们将授权逻辑拆分为一个库,如果调用forRoot()或为配置提供静态值但允许进行动态配置,则可以很好地工作,我使用库中的InjectionToken来提供配置,而无需调用forRoot。

app.module.ts 的代码如下:

Gen.update

现在 authConfigFactory appInitializerFn 之前被调用,导致未定义,如果我在 authConfigFactory 中添加 async 阻止return语句直到其定义,然后将空值提供给AuthGuard,从而导致无效的令牌URL。

如果我在要求promise之前在 appInitializerFn 中手动提供值,则这些值将被转换并且一切正常。但是在那个阶段还没有动态值。

app-config.service.ts 的代码:

let authConfig: any;

export function authConfigFactory() {
  return authConfig;
}

export function appInitializerFn(appConfigService: AppConfigService) {
  return () => {
    return appConfigService.loadAppConfig().then(() => {
      authConfig = {
        clientId: appConfigService.getConfig().CLIENT_ID,
        tokenEndpoint: appConfigService.getConfig().TOKEN_URL,
        redirectURL: "http://localhost",
      };
    });
  };
};

@NgModule({
.....
  imports: [
..
AuthLib
],
  providers: [
    AppConfigService,
    {
      provide: APP_INITIALIZER,
      useFactory: appInitializerFn,
      multi: true,
      deps: [AppConfigService]
    },
    AuthLibService,
    {
      provide: 'authConfig',
      useFactory: authConfigFactory,
      deps: []
    },
.....
]
bootstrap: [AppComponent]
})
export class AppModule { }

要使这项工作有效的库或代码中缺少什么?

我对Angular政权有些陌生,即使我犯了一些愚蠢的错误,也要让我知道。

1 个答案:

答案 0 :(得分:0)

因此找到了原因和解决方法。将其发布给任何人都会绊到这个问题。

由于APP_INITIALIZER被正确调用。我错过的事情是我使用“ HttpClient”来获取配置,而该配置又调用了ROOT中定义的任何HTTP_INTERCEPTORS,并最终导致了Authentication Service的初始化,而后者又需要auth config作为构造函数中的令牌注入。

因此,即使在获取值之前也会注入令牌,从而导致令牌变为未定义/空。

解决方案虽然很简单,但我们可以使用

  1. HttpBackend以获取json或
  2. 在main.ts或
  3. 中获取json
  4. 防止为该json路径调用拦截器。

在我的情况下,第3点是不可能的,因为我想对所有通信进行严格控制,而第2点有点笨拙。我们采用了方法1.共享修改后的代码以供参考。

import { Injectable } from '@angular/core';
import { HttpClient, HttpBackend } from '@angular/common/http';
import { environment } from 'src/environments/environment';
import { AppConfig } from '../_models/app-config';
import { LoggingService } from './logging.service';

@Injectable()
export class AppConfigService {
  static appConfig : AppConfig;
  private dataLoc: string;
  constructor(private handler: HttpBackend,
              private logger: LoggingService) { }

  loadAppConfig() {
      if(environment.production){
        this.dataLoc = '/assets/data/appConfig.json';
      }
      else{
        this.dataLoc = '/assets/data/appConfig-dev.json';
      }
    return  new HttpClient(this.handler).get(this.dataLoc)
      .toPromise()
      .then((data:AppConfig) => {
        this.logger.info(data);
        AppConfigService.appConfig = data;
      });
  }
  getConfig() {
    return AppConfigService.appConfig;
  }
}

由于@ysf,您的最小示例使我想到,如果它在一般情况下正常工作,则在初始化过程中会调用authconfig。