微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

模块中的 Angular APP_INITIALIZER 无法正常工作

如何解决模块中的 Angular APP_INITIALIZER 无法正常工作

我有 auth 模块,它在应用程序初始化之前导入和设置 msal 配置。我正在使用 APP_INITIALIZER 来阻止应用程序的初始化并获取 MSAL-ANGULAR 的配置。 问题仅与 Firefox 有关。该应用程序在 Chrome、Egde、Safari 上运行良好,但在 Firefox 上运行不正常。在与 Firefox 不同的所有其他浏览器上,APP_INITIALIZER 会阻止启动,直到加载 config.json。 我注意到的是 MSALInstanceFactory 在 initializerFactory 函数之前被调用

我在 auth.module 中使用的代码

export function initializerFactory(env: ConfigService,configUrl: string): any {
// APP_INITIALIZER,angular doesnt starts application untill it completes loading config.json
  const promise = env.init(configUrl).then(val => {});
  return () => promise;
}

export function loggerCallback(logLevel: LogLevel,message: string): void {
   console.log(message);
}

export function MSALInstanceFactory(configService: ConfigService,constant: SecurityConstants): IPublicclientApplication {
   return new PublicclientApplication({
      auth: {
         clientId: configService.getSettings('clientId'),redirectUri: configService.getSettings('redirectUri'),authority: configService.getSettings('authority'),},cache: {
         cacheLocation: browserCacheLocation.LocalStorage,storeAuthStateInCookie: isIE,system: {
         loggerOptions: {
            loggerCallback,logLevel: LogLevel.Info,piiLoggingEnabled: false,});
}

export function MSALInterceptorConfigFactory(configService: ConfigService,constant: SecurityConstants): MsalInterceptorConfiguration {
   const protectedResourceMap = new Map<string,Array<string>>();
   protectedResourceMap.set('/*/',[configService.getSettings('scope')]);
   return {
      interactionType: InteractionType.Redirect,protectedResourceMap,};
}

export function MSALGuardConfigFactory(configService: ConfigService,constant: SecurityConstants): MsalGuardConfiguration {
   return {
      interactionType: InteractionType.Redirect,authRequest: {
         scopes: [configService.getSettings('scope')],};
}

@NgModule({
   imports: [MsalModule]
})
export class AuthModule {
   static forRoot(configFile: string) {
      return {
         ngModule: AuthModule,providers: [
            ConfigService,MsalService,{ provide: AUTH_CONfig_URL_TOKEN,useValue: configFile },{
               provide: APP_INITIALIZER,useFactory: initializerFactory,deps: [ConfigService,AUTH_CONfig_URL_TOKEN,SecurityConstants],multi: true,{
               provide: HTTP_INTERCEPTORS,useClass: MsalInterceptor,{
               provide: MSAL_INSTANCE,useFactory: MSALInstanceFactory,// this is initiated before APP_INITIALIZER 
               deps: [ConfigService,{
               provide: MSAL_GUARD_CONfig,useFactory: MSALGuardConfigFactory,{
               provide: MSAL_INTERCEPTOR_CONfig,useFactory: MSALInterceptorConfigFactory,MsalGuard,MsalbroadcastService,],};
   }
}

ConfigService 中的代码

   @Injectable({
       providedIn: 'root',})
    export class ConfigService {
       config: any;
       private http: HttpClient;
    
       constructor(private readonly httpHandler: HttpBackend) {
          this.http = new HttpClient(httpHandler);
       }
    
       init(endpoint: string): Promise<boolean> {
          let promise = new Promise<boolean>((resolve,reject) => {
             this.http
                .get<ConfigResponse>(endpoint)
                .pipe(map((res) => res))
                .subscribe(
                   (value) => {
                         this.config = value;
                   },(error) => {
                      reject(false);
                   },() => {
                      resolve(true);
                   }
                );
          });
             return promise;
       }
    
       getSettings(key?: string | Array<string>): any {
          if (!key || (Array.isArray(key) && !key[0])) {
             return this.config;
          }
    
          if (!Array.isArray(key)) {
             key = key.split('.');
          }
    
          let result = key.reduce((acc: any,current: string) => acc && acc[current],this.config);
    
          return result;
       }
    }

app.module 中的代码

@NgModule({
   declarations: [AppComponent],imports: [
      AuthModule.forRoot('assets/config.json'),CommonModule,browserModule,browserAnimationsModule,HttpClientModule,RouterModule
   ],bootstrap: [AppComponent,MsalRedirectComponent],})
export class AppModule {}

解决方法

我发现 APP_INITIALIZER 并不能保证您的配置服务首先完成。此问题也在此处报告:https://github.com/angular/angular/issues/23279 遗憾的是仍未解决。 最初 MSAL_Instance 在此之前加载,为了解决该问题,我更改了 main.ts 引导模块。

    // main.ts
function bootstrapFailed(val) {
    document.getElementById('bootstrap-fail').style.display = 'block';
    console.error('bootstrap-fail',val);
}

fetch('config.json')
    .then(response => response.json())
    .then(config => {
        if (!config || !config['isConfig']) {
            bootstrapFailed(config);
            return;
        }

   // Store the response somewhere that your ConfigService can read it.
   window['tempConfigStorage'] = config;

    platformBrowserDynamic()
            .bootstrapModule(AppModule)
            .catch(bootstrapFailed);
    })
    .catch(bootstrapFailed);

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。