【问题标题】:Runtime Configuration for Angular 6+ ApplicationsAngular 6+ 应用程序的运行时配置
【发布时间】:2019-01-27 05:48:59
【问题描述】:

在 Angular 应用程序运行时加载环境特定配置的推荐最佳做法是什么? Angular 文档提到了 APP_INITIALIZER 的使用,但是对于诸如使用 .forRoot() 约定的导入模块的运行时配置之类的加载过程来说,这还不够早。

在我的用例中,我有一个通过核心模块构建和导入的身份验证服务,该核心模块由 App 模块导入。我正在使用的身份验证库(angular-oauth2-oidc 库)允许在导入模块时配置自动附加访问令牌(请参阅this segment)。由于我正在使用的构建环境中存在一些限制,仅允许我生成一个通用构建包以部署到所有环境,因此我无法通过使用不同的 environment.ts 文件来动态设置值。

最初的想法是使用 index.html 页面上的 fetch API 将包含配置的 JSON 文件加载到全局变量中,但由于调用是异步的,因此配置可能不会完全加载核心模块的导入发生。

【问题讨论】:

    标签: javascript angular deployment angular-cli web-deployment


    【解决方案1】:

    这是我的配置设置的一部分,目的是让我的应用程序通过构建管道并花费了我数天时间。我最终找到了一个使用APP_INITIALIZER 加载REST 服务并为我的应用程序构建AppConfigService 的解决方案。我正在使用相同的 angular-oauth2-oidc 库。

    我对此问题的解决方案不是在其 forRoot() 方法中设置 OAuthModule。在任何通过APP_INITIALIZER 的配置可用之前调用它 - 这会在应用于forRoot() 方法的配置对象时导致未定义的值。

    但我们需要在 http 标头中添加一个标记。所以我使用http拦截器来附加令牌,如here所述。诀窍是在工厂中设置 OAuthModuleConfig。显然,这是在应用程序初始化后调用的。

    配置模块

    @NgModule({
      imports: [
        // no config here
        OAuthModule.forRoot(),
      ],
      providers: [
       {
        provide: HTTP_INTERCEPTORS,
        useFactory: authenticationInterceptorFactory,
        deps: [OAuthStorage, AuthenticationErrorHandler, OAuthModuleConfig],
        multi: true
       }
     ]
    })
    

    拦截器工厂

    const authenticationInterceptorFactory = (oAuthService: OAuthStorage, authenticationErrorHandler: AuthenticationErrorHandler, oAuthModuleConfig: OAuthModuleConfig) => {
    const config = {
     resourceServer: {
      allowedUrls: [
       // Include config settings here instead
       AppConfigService.settings.apiURL,
       AppConfigService.settings.anotherApiURL,
      ]
      sendAccessToken: true
     },
    }
    return new AuthenticationInterceptor(oAuthService, authenticationErrorHandler, config);
    };
    

    【讨论】:

    • 在这种情况下,您是否使用自己的自定义HttpInterceptor?我正在探索利用库中内置的 DefaultOAuthInterceptor 的方法,这就是为什么我最初试图找到方法来初始化所需的值以作为 forRoot 方法中的配置对象传递。
    • 我使用上面链接的 HttpInterceptor 并更改了一些细节(主要是 rxjs6)。似乎无法在 forRoot() 方法中配置所需的值,因为它是在 APP_INITIALIZER 之前调用的。
    • @vaci 你真的拯救了我的一天(或一周)。我无法在提供程序中获取 OAuthModuleConfig 值,因为提供程序不能异步工作,也无法在 APP_INITIALIZER 中设置它。我总是很接近,但最终得到了 Promises 而不是实际值......所以你创建一个新的拦截器并忽略 OAuthModuleConfig 的技巧非常完美。简单而优雅。谢谢!!!
    【解决方案2】:

    我创建了一个库 angular-runtime-config 用于为 Angular 加载运行时配置。

    简单使用示例

    您的自定义Configuration 类:

    export class Configuration {
      readonly apiUrl!: string; // only example
      readonly apiKey?: string; // only example
      // add some other configuration parameters
    }
    

    注册angular-runtime-config 模块并声明要加载哪些配置文件。例如,您可以通过应用程序 URL 来确定它,甚至可以在工厂中使用 Angular 注入器或使工厂异步。

    import { AngularRuntimeConfigModule } from 'angular-runtime-config';
    
    @NgModule({
      ...
      imports: [
        ...
        AngularRuntimeConfigModule.forRoot(Configuration, {
          urlFactory: () => [ 'config/config.common.json', 'config/config.DEV.json' ]
        })
      ],
    }
    

    然后在任何注入上下文中请求您的 Configuration 类。

    @Injectable({...})
    export class SomeService {
      constructor(private readonly config: Configuration) {}
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-08
      • 2019-06-25
      • 2020-01-03
      • 2019-03-24
      • 1970-01-01
      • 2018-12-14
      • 2018-11-23
      • 1970-01-01
      相关资源
      最近更新 更多