Node.js设置环境特定的配置以与Everyauth一起使用


117

我正在使用node.js + express.js + everyauth.js。我已经将所有我的Everyauth逻辑移到了模块文件中

var login = require('./lib/everyauthLogin');

在其中,我使用密钥/秘密组合加载我的oAuth配置文件:

var conf = require('./conf');
.....
twitter: {
    consumerKey: 'ABC', 
    consumerSecret: '123'
}

这些代码对于不同的环境是不同的-开发/登台/生产,因为回调是针对不同的URL的。

如何在环境配置中设置它们以筛选所有模块,或者可以将路径直接传递到模块中?

在环境中设置:

app.configure('development', function(){
  app.set('configPath', './confLocal');
});

app.configure('production', function(){
  app.set('configPath', './confProduction');
});

var conf = require(app.get('configPath'));

传递

app.configure('production', function(){
  var login = require('./lib/everyauthLogin', {configPath: './confProduction'});
});

?希望有道理


通过使用module = function而不是对象,我找到了一个使用以下想法的解决方案,我可以评估process.env.NODE_ENV并为环境返回正确的对象。有点混乱,但有效。
andy t

请原谅无耻的自我推广,但我为node.js编写了一个模块,该模块将通过单独的文件和命令行开关进行此操作:node-configure
Randolpho

Answers:


192

我的解决方案

使用加载应用

NODE_ENV=production node app.js

然后设置config.js为功能而不是对象

module.exports = function(){
    switch(process.env.NODE_ENV){
        case 'development':
            return {dev setting};

        case 'production':
            return {prod settings};

        default:
            return {error or other settings};
    }
};

然后按照Jans解决方案加载文件并创建一个新实例,如果需要,我们可以传递一个值,在这种情况下process.env.NODE_ENV是全局的,因此不需要。

var Config = require('./conf'),
    conf = new Config();

然后,我们可以像以前一样完全访问config对象的属性

conf.twitter.consumerKey

2
为什么在这里使用new?
bluehallu's

5
我第二个@bluehallu。有new必要吗?
Sung Cho 2015年

2
Windows中的等效设置为SET NODE_ENV = development
mujaffars,2015年

3
而不是做new。我会在config.js....Config = function(){...}; module.exports = Config()
Atu

如果我有50台Web服务器该怎么办?在这种情况下,很难在每台服务器上手动启动脚本
Rajesh

60

您可能还具有一个以NODE_ENV为顶层的JSON文件。IMO,这是表达配置设置的更好方法(与使用返回设置的脚本相反)。

var config = require('./env.json')[process.env.NODE_ENV || 'development'];

env.json的示例:

{
    "development": {
        "MONGO_URI": "mongodb://localhost/test",
        "MONGO_OPTIONS": { "db": { "safe": true } }
    },
    "production": {
        "MONGO_URI": "mongodb://localhost/production",
        "MONGO_OPTIONS": { "db": { "safe": true } }
    }
}

嗨,您能否解释一下为什么您认为这是表达配置设置的更好方法(与使用返回设置的脚本相反)。?
Venkat Kotra 2014年

14
我想这并没有太大的区别。心理上,当我看到JSON时,我认为是“静态数据”,而当我看到JS文件时,我认为其中存在一些逻辑。同样,使用.json类型的另一个好处是其他语言可以导入同一文件。
mattwad 2014年

1
@VenkatKotra配置通常被认为是静态的,因此最好用json,yaml,ini等声明性地表示。必须执行的命令必须使用产生该状态的脚本,sortof暗示动态的情况正在发生,这很糟糕。
最大

9
请注意,此方法在源代码管理中公开凭据。
Pier-Luc Gendreau

我可以为登台和生产制作差异网址吗?
亚历克斯

34

一个非常有用的解决方案是使用config模块

安装模块后:

$ npm install config

您可以创建一个default.json配置文件。(您可以使用扩展名为.json5的JSON或JS对象)

例如

$ vi config/default.json

{
  "name": "My App Name",
  "configPath": "/my/default/path",
  "port": 3000
}

环境配置文件或本地开发环境的本地配置文件可以覆盖此默认配置:

production.json可能是:

{
  "configPath": "/my/production/path",
  "port": 8080
}

development.json可能是:

{
  "configPath": "/my/development/path",
  "port": 8081
}

在本地PC中,您可以具有覆盖所有环境的local.json,也可以具有特定的本地配置,例如local-production.jsonlocal-development.json

加载顺序的完整列表

在您的应用程序内部

在您的应用中,您只需要配置和所需的属性。

var conf = require('config'); // it loads the right file
var login = require('./lib/everyauthLogin', {configPath: conf.get('configPath'));

加载应用

使用以下命令加载应用程序:

NODE_ENV=production node app.js

永久设置正确的环境或pm2

永远:

NODE_ENV=production forever [flags] start app.js [app_flags]

PM2(通过外壳):

export NODE_ENV=staging
pm2 start app.js

PM2(通过.json):

process.json

{
   "apps" : [{
    "name": "My App",
    "script": "worker.js",
    "env": {
      "NODE_ENV": "development",
    },
    "env_production" : {
       "NODE_ENV": "production"
    }
  }]
}

然后

$ pm2 start process.json --env production

该解决方案非常干净,并且可以轻松为生产/登台/开发环境以及本地设置设置不同的配置文件。


npm install config --save,不是更好吗?
stackdave

14

简单来说

这种设置既简单又优雅:

env.json

{
  "development": {
      "facebook_app_id": "facebook_dummy_dev_app_id",
      "facebook_app_secret": "facebook_dummy_dev_app_secret",
  }, 
  "production": {
      "facebook_app_id": "facebook_dummy_prod_app_id",
      "facebook_app_secret": "facebook_dummy_prod_app_secret",
  }
}

common.js

var env = require('env.json');

exports.config = function() {
  var node_env = process.env.NODE_ENV || 'development';
  return env[node_env];
};

app.js

var common = require('./routes/common')
var config = common.config();

var facebook_app_id = config.facebook_app_id;
// do something with facebook_app_id

要以生产模式运行: $ NODE_ENV=production node app.js


详细地

该解决方案来自:http : //himanshu.gilani.info/blog/2012/09/26/bootstraping-a-node-dot-js-app-for-dev-slash-prod-environment/,请查看更多详情。


5

我们这样做的方法是在使用环境启动应用程序时传递一个参数。例如:

node app.js -c dev

然后在app.js中加载dev.js作为配置文件。您可以使用optparse-js解析这些选项。

现在,您有了一些依赖于此配置文件的核心模块。当您这样编写它们时:

var Workspace = module.exports = function(config) {
    if (config) {
         // do something;
    }
}

(function () {
    this.methodOnWorkspace = function () {

    };
}).call(Workspace.prototype);

然后可以这样调用它app.js

var Workspace = require("workspace");
this.workspace = new Workspace(config);

我宁愿将所有逻辑保留在app.js app.configure('development代码中,但会看看我是否可以在其中使用该解决方案
andy t

更新至此答案:Architect是一个依赖管理框架,可以更好地解决此问题。
Jan Jongboom

5

一种优雅的方法是使用.env文件在本地覆盖生产设置。无需命令行开关。不需要文件中所有这些逗号和括号config.json在这里查看我的答案

示例:在我的机器上,.env文件是这样的:

NODE_ENV=dev
TWITTER_AUTH_TOKEN=something-needed-for-api-calls

我的本地.env变量覆盖所有环境变量。但是,在登台服务器或生产服务器(也许它们在heroku.com上)上,环境变量已预先设置为舞台NODE_ENV=stage或生产NODE_ENV=prod


4

在部署服务器中设置环境变量(例如:类似于NODE_ENV = production)。您可以通过process.env.NODE_ENV访问您的环境变量。查找以下用于全局设置的配置文件

const env = process.env.NODE_ENV || "development"

const configs = {
    base: {
        env,
        host: '0.0.0.0',
        port: 3000,
        dbPort: 3306,
        secret: "secretKey for sessions",
        dialect: 'mysql',
        issuer : 'Mysoft corp',
        subject : 'some@user.com',
    },
    development: {
        port: 3000,
        dbUser: 'root',
        dbPassword: 'root',

    },
    smoke: {
        port: 3000,
        dbUser: 'root',
    },
    integration: {
        port: 3000,
        dbUser: 'root',
    },
    production: {
        port: 3000,
        dbUser: 'root',
    }
};

const config = Object.assign(configs.base, configs[env]);

module.exports= config;

base包含所有环境的通用配置。

然后导入其他模块,例如

const config =  require('path/to/config.js')
console.log(config.port)

快乐编码...


3

如何使用nodejs-config模块以更优雅的方式执行此操作。

此模块能够根据您的计算机名称设置配置环境。之后,当您请求配置时,您将获得特定于环境的值。

例如,假设您有两台名为pc1和pc2的开发机器,以及一台名为pc3的生产机器。每当在pc1或pc2中的代码中请求配置值时,您都必须获得“开发”环境配置,而在pc3中,您必须获得“生产”环境配置。可以这样实现:

  1. 在config目录中创建一个基本配置文件,说“ app.json”并向其中添加所需的配置。
  2. 现在,只需在config目录中创建与您的环境名称匹配的文件夹,在本例中为“开发”和“生产”。
  3. 接下来,创建要覆盖的配置文件并在环境目录中为每个环境指定选项(注意,您不必指定基本配置文件中的每个选项,而只需指定要覆盖的选项即可。环境配置文件将在基本文件上“层叠”。)

现在,使用以下语法创建新的配置实例。

var config = require('nodejs-config')(
   __dirname,  // an absolute path to your applications 'config' directory
   {
      development: ["pc1", "pc2"],
      production: ["pc3"],

   }
);

现在,您可以获得任何配置值,而不必担心这样的环境:

config.get('app').configurationKey;

0

这个答案不是什么新鲜事物。它类似于@andy_t提到的内容。但是我使用以下模式有两个原因。

  1. 干净的实现,没有外部npm依赖项

  2. 将默认配置设置与基于环境的设置合并。

JavaScript实现

const settings = {
    _default: {
       timeout: 100
       baseUrl: "http://some.api/",
    },
    production: {
       baseUrl: "http://some.prod.api/",
    },
}
// If you are not using ECMAScript 2018 Standard
// https://stackoverflow.com/a/171256/1251350
module.exports = { ...settings._default, ...settings[process.env.NODE_ENV] }

我通常在节点项目中使用打字稿。以下是我复制粘贴的实际实现。

打字稿实施

const settings: { default: ISettings, production: any } = {
    _default: {
        timeout: 100,
        baseUrl: "",
    },
    production: {
        baseUrl: "",
    },
}

export interface ISettings {
    baseUrl: string
}

export const config = ({ ...settings._default, ...settings[process.env.NODE_ENV] } as ISettings)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.