我一直在研究一些Node应用程序,我一直在寻找一种存储与部署相关的设置的良好模式.在Django世界(我来自哪里),通常的做法是拥有一个settings.py
包含标准设置(时区等)的文件,然后是一个local_settings.py
用于部署特定设置的文件,即.什么数据库交谈,什么memcache套接字,管理员的电子邮件地址等.
我一直在寻找类似Node的模式.只是一个配置文件会很好,所以它不必被其他所有东西堵塞app.js
,但我发现有一种方法可以在一个不在源代码控制中的文件中进行特定于服务器的配置.相同的应用程序可以在不同的服务器上部署,具有完全不同的设置,并且必须处理合并冲突以及所有这些不是我的乐趣.
那么是否有某种框架/工具,或者每个人都自己一起破解某些东西?
我用package.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
等等访问我的东西...如果我不想在源代码管理中存储密码,我可以使用硬编码参数或存储在环境变量中的参数.
我还生成一个package.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中,为我的生产服务器添加了遥控器.
从Node v0.5.x开始,您可以要求JSON文件(引用此答案)
config.json:
{ "username" : "root", "password" : "foot" }
app.js:
var config = require('./config.json'); log_in(config.username, config.password);
很久以后,我发现了一个非常好的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.
我的解决方案很简单:
在./config/index.js中加载环境配置
var env = process.env.NODE_ENV || 'development' , cfg = require('./config.'+env); module.exports = cfg;
在./config/config.global.js中定义一些默认值
var config = module.exports = {}; config.env = 'development'; config.hostname = 'dev.example.com'; //mongo database config.mongo = {}; config.mongo.uri = process.env.MONGO_URI || 'localhost'; config.mongo.db = 'example_dev';
覆盖./config/config.test.js中的默认值
var config = require('./config.global'); config.env = 'test'; config.hostname = 'test.example'; config.mongo.db = 'example_test'; module.exports = config;
在./models/user.js中使用它:
var mongoose = require('mongoose') , cfg = require('../config') , db = mongoose.createConnection(cfg.mongo.uri, cfg.mongo.db);
在测试环境中运行您的应用:
NODE_ENV=test node ./app.js
这里有更详细的解释:http://www.chovy.com/node-js/managing-config-variables-inside-a-node-js-application/
你也可以看看遵循12因素应用程序原则的dotenv.
我曾经使用node-config,但出于这个原因创建了dotenv.它完全受到ruby的dotenv库的启发.
用法很简单:
var dotenv = require('dotenv'); dotenv.load();
然后你只需创建一个.env文件并将设置放在那里:
S3_BUCKET=YOURS3BUCKET SECRET_KEY=YOURSECRETKEYGOESHERE OTHER_SECRET_STUFF=my_cats_middle_name
这是nodejs的dotenv.
你们是否使用npm来启动脚本(env等)?
如果您使用.env
文件,可以将它们包含在您的文件中package.json
并使用npm来获取/启动它们.
例:
{ "name": "server", "version": "0.0.1", "private": true, "scripts": { "start": "node test.js", "start-dev": "source dev.env; node test.js", "start-prod": "source prod.env; node test.js" }, "dependencies": { "mysql": "*" } }
然后运行npm脚本:
$ npm start-dev
它在这里描述https://gist.github.com/ericelliott/4152984 所有归功于Eric Elliot
您还可以查看node-config,它根据$ HOST和$ NODE_ENV变量(有点像RoR)加载配置文件:文档.
这可以针对不同的部署设置(相当有用development
,test
或production
).
只需做一个简单settings.js
的exports
:
exports.my_password = 'value'
然后,在您的脚本中,执行以下操作require
:
var settings = require('./settings.js');
您现在的所有设置都将通过settings
变量提供:
settings.my_password // 'value'
我要把帽子放到戒指上,因为这些答案都没有解决任何系统所需的所有关键组件.注意事项:
公共配置(可以通过前端看到)与私人配置(家伙mograbi得到这一个权利).并确保这些是分开的.
像钥匙一样的秘密
默认值与特定于环境的覆盖
前端捆绑
这是我如何配置:
config.default.private.js
- 在版本控制中,这些是默认配置选项,只能由后端查看.
config.default.public.js
- 在版本控制中,这些是后端和前端可以看到的默认配置选项
config.dev.private.js
- 如果您需要dev的不同私有默认值.
config.dev.public.js
- 如果您需要dev的不同公共默认值.
config.private.js
- 不在版本控制中,这些是覆盖的特定于环境的选项 config.default.private.js
config.public.js
- 不在版本控制中,这些是覆盖的特定于环境的选项 config.default.public.js
keys/
- 每个文件存储某种不同秘密的文件夹.这也不受版本控制(键不应该受版本控制).
我使用普通的javascript文件进行配置,因此我充分掌握了javascript语言(包括注释和执行操作的能力,例如在特定于环境的文件中加载默认配置文件,以便可以覆盖它们).如果你想使用环境变量,你可以在这些配置文件中加载它们(因为我不建议使用json文件,我建议不要使用env变种 - 你没有编译语言的强大功能来构建你的配置).
每个密钥位于单独文件中的原因是供安装程序使用.这允许您拥有一个在机器上创建密钥的安装程序,并将它们存储在密钥文件夹中.如果没有这个,加载无法访问密钥的配置文件时,安装程序可能会失败.通过这种方式,您可以遍历目录并加载该文件夹中的所有密钥文件,而无需担心代码的任何给定版本中存在的内容和不存在的内容.
由于您可能在私有配置中加载了密钥,因此您绝对不希望在任何前端代码中加载私有配置.虽然将前端代码库与后端完全分离可能非常理想,但很多时候PITA是阻止人们进行操作的一大屏障,因此私有vs公共配置.但我做了两件事来防止在前端加载私有配置:
我有一个单元测试,确保我的前端捆绑包不包含私有配置中的一个密钥.
我的前端代码位于与后端代码不同的文件夹中,我有两个不同的文件名为"config.js" - 每端一个.对于后端,config.js加载私有配置,对于前端,它加载公共配置.然后你总是只需要('config')并且不用担心它来自哪里.
最后一件事:您的配置应该通过一个完全独立的文件加载到浏览器中,而不是任何其他前端代码.如果捆绑前端代码,则应将公共配置构建为完全独立的捆绑包.否则,您的配置不再是真正的配置 - 它只是代码的一部分.配置需要能够在不同的机器上不同.
Convict是另一个添加模式进行验证的选项.与nconf一样,它支持从环境变量,参数,文件和json对象的任意组合加载设置.
自述文件中的示例:
var convict = require('convict'); var conf = convict({ env: { doc: "The applicaton environment.", format: ["production", "development", "test"], default: "development", env: "NODE_ENV" }, ip: { doc: "The IP address to bind.", format: "ipaddress", default: "127.0.0.1", env: "IP_ADDRESS", }, port: { doc: "The port to bind.", format: "port", default: 0, env: "PORT" } });
入门文章: 使用node-convict驯服配置
您可以将Konfig用于特定于环境的配置文件.它自动加载json或yaml配置文件,它具有默认值和动态配置功能.
Konfig repo的一个例子:
File: config/app.json ---------------------------- { "default": { "port": 3000, "cache_assets": true, "secret_key": "7EHDWHD9W9UW9FBFB949394BWYFG8WE78F" }, "development": { "cache_assets": false }, "test": { "port": 3001 }, "staging": { "port": #{process.env.PORT}, "secret_key": "3F8RRJR30UHERGUH8UERHGIUERHG3987GH8" }, "production": { "port": #{process.env.PORT}, "secret_key": "3F8RRJR30UHERGUH8UERHGIUERHG3987GH8" } }
开发中:
> config.app.port 3000
在生产中,假设我们开始申请 $ NODE_ENV=production PORT=4567 node app.js
> config.app.port 4567
更多细节:https://github.com/vngrs/konfig
我将创建一个文件夹作为配置文件命名为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'); } });