【问题标题】:Loading configuration files in Angular 6在 Angular 6 中加载配置文件
【发布时间】:2019-11-04 10:14:18
【问题描述】:

我正在尝试了解如何在 Angular 6 中加载配置文件,我目前有一个带有以下代码的 ConfigureService 用于加载文件:

configUrl = '../assets/config.json';
config: Config;

load() {
  console.log('loading configuration');
  this.getConfig().subscribe(
    (data: Config) => {
      console.log('Config request success');
      (this.config = data);
      console.log(this.config)
    }
  );
}

private getConfig() {
  return this.http.get<Config>(this.configUrl);
}

在ConfigureService的构造函数中调用load的地方

我使用此服务为我的 api 消费者服务获取我的 Url 字符串,它确实运行成功(控制台日志显示在开发窗口中),只是没有及时让这些服务在他们的OnInit 方法和其他服务在尝试从未定义的配置对象中提取字符串时抛出错误。

我试图通过在 app.module 中指定它们并在启动之前加载它们来读取它们,如下所示:

https://gist.github.com/fernandohu/122e88c3bcd210bbe41c608c36306db9

但是当我尝试该方法时,它告诉我在服务器上找不到文件,并且控制台中的错误返回 404,即使指定的路径是正确的。

如何确保配置服务首先运行,以便依赖于它的其他服务在它完成初始化之前不会尝试检索数据?

【问题讨论】:

    标签: angular angular6


    【解决方案1】:

    这是一个非常好的问题,我们也有不同的服务器(Dev、QC、Stage、Prod), 因此为每个环境创建单独的构建是非常耗时的过程, 我从未尝试过为每个环境创建单独的环境文件的这种方法, 我们通过将 Api Urls 和常量存储在 json 文件中解决了这个问题。

    首先创建一个 json 文件并将其放在 assets 文件夹中。

    Config.json

    {
        "url":{
        "apiUrl": "http://localhost:58357/"
        }
    }
    

    创建一个模型类,其属性应与 Config.json 文件具有相同名称

    Config.ts

     export class Config {
        url: {
            apiUrl: string;
        };
    }
    

    创建服务以导入 Config.json 文件

    app.config.service.ts

    import { Injectable } from '@angular/core';
    import { Config } from './models/config';
    import { HttpClient, HttpBackend, HttpResponse } from '@angular/common/http';
    import { Observable } from '../node_modules/rxjs';
    import { map } from 'rxjs/operators';
    
    @Injectable({
    providedIn: 'root'
    })
    export class AppConfig {
    
    static Settings: Config;
    private http: HttpClient;
    constructor(private httpBackEnd: HttpBackend) {
        this.http = new HttpClient(httpBackEnd);
    }
    load() {
        const jsonFile = 'assets/config.json';
        return new Promise<void>((resolve, reject) => {
        this.http.get(jsonFile).toPromise().then((response: Config) => {
           AppConfig.Settings = <Config>response;
           resolve();
        }).catch((response: any) => {
           reject(`Could not load file '${jsonFile}': ${JSON.stringify(response)}`);
        });
        });
     }
    }
    

    app.module.ts

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule, APP_INITIALIZER } from '@angular/core';
    import { AppComponent } from './app.component';
    import { AppConfig } from '../app.config.service';
    import { HttpClientModule } from '../../node_modules/@angular/common/http';
    
    
    export function initConfig(appConfig: AppConfig) {
    return () => appConfig.load();
    }
    
    @NgModule({
    declarations: [
    AppComponent
    ],
      imports: [
      BrowserModule,
      HttpClientModule,
      ],
    providers: [
     AppConfig, { provide: APP_INITIALIZER, useFactory: initConfig, deps: [AppConfig], multi: true },
      ],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    

    在您想要使用存储在 json 文件中的密钥的任何组件文件中导入 AppConfig。

    app.component.ts

    import { Component } from '@angular/core';
    import { AppConfig } from '../app.config.service';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
     })
     export class AppComponent {
     title = 'ConstantsManagerDemo';
     constructor() {
     const apiUrl = AppConfig.Settings.url.apiUrl;
     alert(apiUrl);
      }
     }
    

    转到 tsconfig.json 文件并添加

    "allowSyntheticDefaultImports" :true,  
    under compilerOptions
    

    【讨论】:

    • 这仅在本地机器上运行时有效,但在测试服务器上部署时失败。当 Angular 在客户端浏览器上运行时,它无法访问已部署 Angular 包的服务器上的资产文件夹。在客户端浏览器上运行时没有办法 angular 将能够找到此行的文件 const jsonFile = 'assets/config.json';
    • @Sike12,你在tsconfig.json文件的compilerOptions下设置"allowSyntheticDefaultImports" :true
    • 我做了,但它不起作用。我有一种感觉,因为我在 azure 上部署应用程序的工作方式不同。
    • 可能是,因为我已经在生产服务器上部署了一个具有相同代码的站点并且它工作正常。
    【解决方案2】:

    您可能想要使用 async/await 或转发承诺:

    
        config: Promise<Config>;
    
        load() {
          console.log('loading configuration');
          this.config = requestConfig();
        }
    
        private requestConfig(): Promise<Config> {
           return this.http.get<Config>(this.configUrl).toPromise();
        }
    
        // do something asynchronously based on the config
        public async doAsynchonously(consumer: (Config => void)){
          const config = await this.config;
          consumer(config);
        }
    
        // return another promise that someone can react on, or use asynchronously
        // i.e. push handling of asynchronous behavior to the user of the API
        public someSettingFromConfig(): Promise<string> {
           return this.config.then(config => config.somesetting);       
        }
    

    另请参阅:http://www.damirscorner.com/blog/posts/20170127-Angular2TutorialWithAsyncAndAwait.html
    还有:https://labs.encoded.io/2016/12/08/asyncawait-with-angular/

    您可能想做的另一件事是发出同步请求,我在这里给出警告:“同步请求通常对性能不利!”。

        config : Config;
    
        load() {
          this.config = requestConfig();
        }
    
        private requestConfig(): Config {
          const request= new XMLHttpRequest();
          request.open('GET', '/assets/config.json', false);
          if (request.overrideMimeType) {
            request.overrideMimeType('application/json');
          }
          request.send();
          if (request.status === 200) {
            return <Config>JSON.parse(config.responseText);
          }
          // log some error
          return undefined;
        }
    

    【讨论】:

      【解决方案3】:

      按照以下步骤操作:

      • 导入环境
      • 定义本地环境属性
      • 读取配置属性
      import {environment} from '../../environments/environment';
      env = environment;
      public myProperty = this.env.property path
      

      【讨论】:

        猜你喜欢
        • 2017-06-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-27
        • 2018-12-24
        • 2019-09-06
        • 2018-11-12
        • 1970-01-01
        相关资源
        最近更新 更多