在生产环境中访问环境变量Angular 4

7

我希望部署一个angular应用的生产版本,并为用户提供可配置的api url以进行测试。我使用environment.ts文件,但在生产版本构建后,我不知道如何配置变量。

需要采取什么方法?

4个回答

11
环境*.ts文件包含构建时的配置,构建后无法更改。如果您需要在构建后更改配置,则需要将它们放在不同的位置,并在应用程序启动时动态检索它们。
您可以执行以下操作:
步骤1:将json配置文件放在src/assets/config/[envName].json下。
注意:必须是json格式,而不是ts格式。
步骤2:添加一个新的配置服务。
import {Inject, Injectable} from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {Observable} from 'rxjs/Rx';
import {environment} from "../../environments/environment";

/**
 * Declaration of config class
 */
export class AppConfig
{
//Your properties here
  readonly production: boolean;
  readonly name: string;

  readonly apiBaseUrl: string;

}

/**
 * Global variable containing actual config to use. Initialised via ajax call
 */
export let APP_CONFIG: AppConfig;

/**
 * Service in charge of dynamically initialising configuration
 */
@Injectable()
export class AppConfigService
{

  constructor(private http: HttpClient)
  {
  }

  public load()
  {
    return new Promise((resolve, reject) => {

      let confName = environment.name + '.json';
      this.http.get('/assets/config/' + confName).map(res => res as any).catch((error: any): any => {
        reject(true);
        return Observable.throw('Server error');
      }).subscribe((envResponse :any) => {
        let t = new AppConfig();
        //Modify envResponse here if needed (e.g. to ajust parameters for https,...)
        APP_CONFIG = Object.assign(t, envResponse);
        resolve(true);
      });

    });
  }
}

第三步:在主模块中,在声明模块之前添加以下内容:

/**
* Exported function so that it works with AOT
* @param {AppConfigService} configService
* @returns {Function}
*/
export function loadConfigService(configService: AppConfigService): Function 

{
  return () => { return configService.load() }; 
}

第四步:修改模块提供者以添加此内容 提供者: [ …

  AppConfigService,
  { provide: APP_INITIALIZER, useFactory: loadConfigService , deps: [AppConfigService], multi: true },


],

第五步: 在你的代码中,不要使用environment.configXXX,而是使用以下内容

import {APP_CONFIG} from "../services/app-config.service";

//…
return APP_CONFIG.configXXX;

这只是一个简化的例子,如果您使用Angular Universal,则需要进行一些更改,因为在进行HTTP调用时需要使用绝对URL。


1
一个 TypeScript 文件必须在构建时编译。如果该文件是 JSON,则 OP 可以在此之后更改配置。 - P. Moloney
我不明白你指的是什么,我们的代码是由Angular编译器编译成JS后再执行的。 - Akshay Vijay Jain
1
嗨,David,你有一个简单的Plunker演示吗? - OreoFanatics
1
@OreoFanatics 不,我没有。但是我已经清楚地列出了步骤,所以你可以尝试一下,如果有任何错误,请发布出来。这是我在所有的Angular项目中使用的模式。 - David
但是如何在不指定构建环境的情况下自定义config.json? - Nick Borges
显示剩余2条评论

6
您是否在使用Angular-CLI?如果是的话,那么应该很容易。您可以拥有类似于以下内容的东西:
src/
  app/
  environment/
    environment.ts
    environment.prod.ts

简单来说,只需在environment.prod.ts中放置不同的URL地址,您的生产构建就会得到第二个URL地址。例如,假设您的environment.ts文件如下:

{
  "production": false,
  "apiUrl": "http://localhost:8080"
}

将以下内容放入environment.prod.ts中:
{
  "production": true,
  "apiUrl": "https://example.com/api"
}

你可以设置更多的环境,请查看.angular-cli.json和angular-cli存储库中的该部分。
编辑:根据您的评论,您想要更多内容。
引用:
是的,但是在构建之后这仍然不能配置,对吧?因为我不知道用户想要使用什么URL,所以我希望在部署构建之后从外部进行配置。
让我们进一步探讨这种情况。让我们有一个后端客户端:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { apiUrl } from '../environment/environment.ts';
@Injectable()
export class BackendService {
    backendUrl: string = apiUrl;      

    constructor(private httpClient: HttpClient) {}

    get(endpoint: string, params: any): Observable<any> {
      const url= `${this.backendUrl}/${endpoint}`;
      return this.httpClient.get(url, params);
    }
}

简化后,但有效。默认情况下,您可以设置自己的URL。但是,您的组件可以即时设置URL,并从该URL获取其他内容。

现在,下一步是提供您拥有哪些后端。这可以是预配置的数组,或者您可以让客户自由输入URL(简单的输入框)。您可以有一个组件来完成此操作,并配置此服务。您可能还应该为“适当”的后端设置单独的服务,例如身份验证功能所在的服务。但这完全取决于您的情况。


是的,但这在构建之后仍然无法配置,对吧?因为我不知道用户想使用什么URL,所以我想在部署构建后从外部进行配置。 - OreoFanatics

5
  • 将您的配置放在ts文件中,位于assets文件夹中
  • 就像您获取environment.ts一样,获取该文件并使用其配置
  • assets文件夹的内容未被最小化,因此它们也可以在生产构建中进行配置

这个问题解决了吗?还有什么需要问的吗? - Akshay Vijay Jain
我的代码只有这样,哪里出了问题?你能具体说明一下吗?或者在我的Skype ID:learnakshayjain上分享屏幕吗? - Akshay Vijay Jain
我已经更改了URL,但我的构建仍然读取旧的URL(即构建期间存在的那个)。 - OreoFanatics
你需要使用ctrl + c停止编译器,然后重新启动它。 - Akshay Vijay Jain
让我们在聊天中继续这个讨论 - Akshay Vijay Jain
@Akshay Vijay Jain:先生,一旦上述过程完成,我们只需在服务器上上传配置文件而不是整个构建,我说的对吗? - Kapil Soni

2

我们是否真的需要APP_INITIALIZER来加载动态环境变量

除非我们需要一些异步调用来获取它们,否则我建议使用以下方法:

env.js

(function (window) {
  window._env = window._env || {};
  window._env.url= 'http://api-url.com';
}());

index.html

<head>
  <script src="env.js"></script>
</head>
<body>
  <app-root></app-root>
</body>

最后将其添加到angular.json中。

"assets": [
              "any/env.js",

现在你可以在应用程序中使用服务来读取窗口。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接