我一直在开发一些Node应用程序,我一直在寻找一种存储部署相关设置的良好模式。在Django世界(我来自那里),常见的做法是有一个settings.py文件包含标准设置(时区等),然后有一个local_settings.py用于部署特定的设置,即。要与什么数据库通信、什么memcache套接字、管理员的电子邮件地址等等。

我一直在为Node寻找类似的模式。只要一个配置文件就好了,这样它就不必与app.js中的其他所有东西挤在一起,但我发现有一种方法在源代码控制之外的文件中拥有特定于服务器的配置很重要。同一款应用可以部署在不同设置的服务器上,必须处理合并冲突,这不是我的乐趣所在。

那么是否存在某种框架/工具,或者每个人都只是自己拼凑一些东西?


当前回答

在这里,我将全身心地投入其中,因为这些答案中没有一个解决了几乎任何系统都需要的所有关键组件。注意事项:

公共配置(可以从前端看到)vs私有配置(guy mograbi说对了)。并确保它们是分开的。 钥匙一样的秘密 默认值vs特定于环境的覆盖 前端包

以下是我如何进行配置:

config.default.private.js - In version control, these are default configuration options that can only be seen by your backend. config.default.public.js - In version control, these are default configuration options that can be seen by backend and frontend config.dev.private.js - If you need different private defaults for dev. config.dev.public.js - If you need different public defaults for dev. config.private.js - Not in version control, these are environment specific options that override config.default.private.js config.public.js - Not in version control, these are environment specific options that override config.default.public.js keys/ - A folder where each file stores a different secret of some kind. This is also not under version control (keys should never be under version control).

I use plain-old javascript files for configuration so I have the full power of the javascript langauge (including comments and the ability to do things like load the default config file in the environment-specific file so they can then be overridden). If you want to use environment variables, you can load them inside those config files (tho I recommend against using env vars for the same reason I don't recommend using json files - you don't have the power of a programming language to construct your config).

每个键在一个单独的文件中的原因是为了安装程序的使用。这允许您有一个安装程序,在机器上创建密钥并将它们存储在密钥文件夹中。如果不这样做,当你加载无法访问密钥的配置文件时,安装程序可能会失败。通过这种方式,您可以遍历目录并加载该文件夹中的任何关键文件,而不必担心在任何给定版本的代码中哪些存在哪些不存在。

由于您可能在私有配置中加载了密钥,因此您绝对不希望在任何前端代码中加载私有配置。虽然严格来说,将前端代码库与后端代码库完全分离可能更理想,但很多时候,PITA是一个足够大的障碍,阻止人们这样做,从而导致私有配置与公共配置。但是我做了两件事来防止在前端加载私有配置:

我有一个单元测试,确保我的前端包不包含我在私有配置中的一个密钥。 我将前端代码放在与后端代码不同的文件夹中,并且我有两个名为“config.js”的不同文件-一端一个。对于后端,config.js加载私有配置,对于前端,它加载公共配置。然后你总是只需要('config'),而不用担心它来自哪里。

最后一件事:您的配置应该通过一个完全独立于任何其他前端代码的文件加载到浏览器中。如果捆绑前端代码,公共配置应该作为一个完全独立的包构建。否则,你的配置就不再是真正的配置了——它只是你代码的一部分。配置需要能够在不同的机器上有所不同。

其他回答

我用一个包装。Json为我的包和config.js为我的配置,它看起来像:

var config = {};

config.twitter = {};
config.redis = {};
config.web = {};

config.default_stuff =  ['red','green','blue','apple','yellow','orange','politics'];
config.twitter.user_name = process.env.TWITTER_USER || 'username';
config.twitter.password=  process.env.TWITTER_PASSWORD || 'password';
config.redis.uri = process.env.DUOSTACK_DB_REDIS;
config.redis.host = 'hostname';
config.redis.port = 6379;
config.web.port = process.env.WEB_PORT || 9980;

module.exports = config;

我从我的项目加载配置:

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

然后我可以从config.db_host, config.db_port等访问我的东西…这让我可以使用硬编码的参数,如果我不想在源代码控制中存储密码,也可以使用存储在环境变量中的参数。

我还生成了一个包。Json和插入依赖项部分:

"dependencies": {
  "cradle": "0.5.5",
  "jade": "0.10.4",
  "redis": "0.5.11",
  "socket.io": "0.6.16",
  "twitter-node": "0.0.2",
  "express": "2.2.0"
}

当我将项目克隆到本地机器时,我运行npm install来安装包。更多信息请点击这里。

项目存储在GitHub中,并为我的生产服务器添加了遥控器。

npm i config

In config/default.json
{
    "app": {
        "port": 3000
    },
    "db": {
        "port": 27017,
        "name": "dev_db_name"
    }
}

In config/production.json
{
    "app": {
        "port": 4000
    },
    "db": {
        "port": 27000,
        "name": "prod_db_name"
    }
}

In index.js

const config = require('config');

let appPort = config.get('app.port');
console.log(`Application port: ${appPort}`);

let dbPort = config.get('db.port');
console.log(`Database port: ${dbPort}`);

let dbName = config.get('db.name');
console.log(`Database name: ${dbName}`);

console.log('NODE_ENV: ' + config.util.getEnv('NODE_ENV'));

$ node index.js
Application port: 3000
Database port: 27017
Database name: dev_db_name
NODE_ENV: development

For production
$ set NODE_ENV=production
$ node index.js
Application port: 4000
Database port: 27000
Database name: prod_db_name
NODE_ENV: production

下面是本文启发的一个简洁的方法。它不需要任何额外的包,除了无处不在的lodash包。此外,它还允许您使用特定于环境的覆盖来管理嵌套默认值。

首先,在包的根路径中创建一个配置文件夹,如下所示

package
  |_config
      |_ index.js
      |_ defaults.json
      |_ development.json
      |_ test.json
      |_ production.json

这是index.js文件

const _ = require("lodash");
const defaults = require("./defaults.json");
const envConf = require("./" + (process.env.NODE_ENV || "development") + ".json" );
module.exports = _.defaultsDeep(envConf, defaults);

现在我们假设有一个默认值。像这样的Json

{
  "confKey1": "value1",
  "confKey2": {
    "confKey3": "value3",
    "confKey4": "value4"
  }
}

和发展。像这样的Json

{
  "confKey2": {
    "confKey3": "value10",
  }
}

如果你执行config = require('./config'),你会得到这样的结果

{
  "confKey1": "value1",
  "confKey2": {
    "confKey3": "value10",
    "confKey4": "value4"
  }
}

注意,除了在特定于环境的文件中定义的值外,您可以得到所有的默认值。因此,您可以管理配置层次结构。使用defaultsDeep可以确保您甚至可以拥有嵌套的默认值。

我将创建一个文件夹,配置一个命名为config.js的文件,稍后我会在需要的地方使用这个文件,如下所示

config.js的例子

module.exports = {
    proxyURL: 'http://url:port',
    TWITTER: {
        consumerkey: 'yourconsumerkey',
        consumerSecrete: 'yourconsumersecrete'
    },
    GOOGLE: {
        consumerkey: 'yourconsumerkey',
        consumerSecrete: 'yourconsumersecrete'
    },
    FACEBOOK: {
        consumerkey: 'yourconsumerkey',
        consumerSecrete: 'yourconsumersecrete'
    }
}

然后,如果我想在某处使用这个配置文件

我将首先导入如下

Var config = require('./config');

,我可以访问如下的值

const oauth = OAuth({
    consumer: {
        key: config.TWITTER.consumerkey,
        secret: config.TWITTER.consumerSecrete
    },
    signature_method: 'HMAC-SHA1',
    hash_function(base_string, key) {
        return crypto.createHmac('sha1', key).update(base_string).digest('base64');
    }
});

很久以后,我发现了一个非常好的Node.js模块来管理配置:nconf。

举个简单的例子:

var nconf = require('nconf');

// First consider commandline arguments and environment variables, respectively.
nconf.argv().env();

// Then load configuration from a designated file.
nconf.file({ file: 'config.json' });

// Provide default values for settings not provided above.
nconf.defaults({
    'http': {
        'port': 1337
    }
});

// Once this is in place, you can just use nconf.get to get your settings.
// So this would configure `myApp` to listen on port 1337 if the port
// has not been overridden by any of the three configuration inputs
// mentioned above.
myApp.listen(nconf.get('http:port'));

它还支持在Redis中存储设置,编写配置文件,并且有一个相当可靠的API,并且还得到了一个更受尊敬的Node.js商店Nodejitsu的支持,作为Flatiron框架计划的一部分,所以它应该是相当经得起未来的。

在Github上查看nconf。