在Node.Js / Express应用程序中存储数据库配置的最佳方式是什么?

79
什么是在运行于node.js / Express上的开源应用程序中存储数据库配置(用户名,密码)的最佳方法? 两个具体问题:
  1. 我应该将其放入/lib文件夹中的单独的config.js文件中,例如,并永远不将其包含在公开在GitHub上可用的主代码库中吗?
  2. 要包括配置,是否只需从需要它的文件中使用require('./config.js')即可,还是有更好的方法?
PS如果问题似乎有点简单或者表述不太好,请见谅,因为我刚开始学习 :)
7个回答

125

以下是我如何做到的:

创建一个包含表示配置的对象的config.js文件:

var config = {
development: {
    //url to be used in link generation
    url: 'http://my.site.com',
    //mongodb connection settings
    database: {
        host:   '127.0.0.1',
        port:   '27017',
        db:     'site_dev'
    },
    //server details
    server: {
        host: '127.0.0.1',
        port: '3422'
    }
},
production: {
    //url to be used in link generation
    url: 'http://my.site.com',
    //mongodb connection settings
    database: {
        host: '127.0.0.1',
        port: '27017',
        db:     'site'
    },
    //server details
    server: {
        host:   '127.0.0.1',
        port:   '3421'
    }
}
};
module.exports = config;

然后在我的index.js中(或其他任何地方),

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

然后使用该对象进行处理,例如:

var server = express();
server.listen(config.server.port);
...

太棒了...真的很有帮助,节省了很多时间。 - Wcan
我有一个问题,如何在Angular端使用相同的配置文件来生成开发/生产URL? - Wcan
7
我喜欢在一个文件中有几个可用的配置的想法,但是开发环境和生产环境的配置混合在一起并不好:它们不应该存储在同一个文件中。您不希望将生产数据库密码存储在开发机器上,那太疯狂了!另外:永远不要将此配置文件提交到版本控制。 - jlh
@jlh 完全正确 - 我永远不会在这个文件中存储凭据 - 我要么使用dotenv,要么直接通过shell配置文件导出系统变量。 - Stephen Wright
1
这种方法存在一个问题,如果你正在使用webpack,它会将这个配置文件打包到bundle中。因此,你无法替换不同环境的值。你被迫为不同的环境创建不同的bundles。 - Neeraj Gulia

33

我在运行需要隐藏数据库凭据的玩具应用程序时,会使用 dotenv 模块

将敏感信息放入 .env 文件中(该文件被 .gitignore 忽略),在应用程序中加入 require('dotenv').config(); ;dotenv 会在 process.env 中创建条目,您可以引用它们。

.env 文件:

DATABASE_PASSWORD=mypw
DATABASE_NAME=some_db

引用值:

process.env.DATABASE_PASSWORD

27

不确定这是否是最佳实践,但我个人拥有一个config.json文件,其中存储了我的数据库连接信息。然后我执行以下操作:

// options.js
var fs = require('fs'),
configPath = './config.json';
var parsed = JSON.parse(fs.readFileSync(configPath, 'UTF-8'));
exports.storageConfig=  parsed;

然后我从另一个文件中执行以下操作:

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

var loginData = {
        host: options.storageConfig.HOST,
        user: options.storageConfig.user,
        password: options.storageConfig.password
};

1
如果有帮助的话-- 我将我的配置文件存储在/config目录中,当我运行时出现Error: ENOENT, no such file or directory './config.json'错误。当我在options.js中把 configPath = './config.json' 改成 configPath = __dirname + '/config.json' 时,这个解决方案对我很有效。参考@loganfsmyth 的评论:https://dev59.com/qWYr5IYBdhLWcg3wnrV0 - ozandlb
@anvarik 为什么不将配置文件设为 JSON 对象并将其导出为 Node 模块呢?这样你可以在需要的地方轻松地使用它了。 - Kamalakannan J
这个回复非常老了,请参考@Stepen的答案。 - stackdave
12
在服务器上有一个包含机密凭据的文件是不是一个很大的问题?如果是,那么这个答案就没有帮助,我们还应该做什么?一些人说我们应该使用环境变量-但有人认为它们也很危险,因为服务器上的任何程序都可以读取它们。 - Morris
1
@Vic 我有同样的担忧。我正在寻找一个能够解密加密配置文件的NodeJS库,但当我偶然发现这个并没有看到任何人推荐它时,我以为自己疯了。很高兴看到还有其他人也在考虑同样的事情。 - Matthew Zackschewski
1
我认为这是一个不错的做法,因为我们有一个配置文件,其中包含不同的键需要在不同的环境中具有不同的值。使用 webpack,我们将解决方案捆绑在单个文件中。这样节省了我们的时间。此外,在存储库中不存储机密信息 - 在部署过程中,凭据会在 json 文件中替换为实际值。 - Neeraj Gulia

3

我会像许多Node.js示例中的端口一样,将参数放入args中。你很可能会使用forever、pm2、nodemon来运行你的应用程序。因此,这个变量不会作为你的源代码的一部分被检查,并且它们也是全局可用的。

process.env.PORT
process.env.DATABASE_USER
process.env.DATABASE_PASSWORD


PORT=3000 DATABASE_HOST=localhost DATABASE_USER=admin DATABASE_PASSWORD=mypassword node app.js

export PORT=3000
export DATABASE_HOST=localhost
export DATABASE_PORT=27017
export DATABASE_USER=admin
export DATABASE_PASSWORD=mypassword
node app.js

var server = app.listen(process.env.PORT, function() {
});

var mongoClient = new MongoClient(new Server(process.env.DATABASE_HOST, process.env.DATABASE_PORT));

1
你有相关代码示例吗?我的意思是在 args 中确切地放在哪里?args 是什么?谢谢! - Aerodynamika
我猜这是环境变量?那么我可以这样设置:export PORT=3306 - Nilton Vasques

2
要包含配置文件,只需要从需要它的文件中使用require('./config.js')。但是,是否有更好的方式呢?
存储配置文件的正确方式是像普通的Node.js模块一样编写整个应用程序,并编写一个小型启动文件以调用它。这种方法还允许您使用依赖注入来使用不同的数据库驱动程序。
环境是一个好但并非完美的解决方案。它在所有应用程序之间共享,因此如果您有某些数据希望对它们全部可用,则这是最好的选择。但是,如果您有一个特定应用程序的配置,则不太适用。
PS:请不要使用JSON来存储配置文件,这是最糟糕的想法。 :)

为什么JSON不是一个好主意? - Aerodynamika
2
主要是因为它不支持注释和尾随逗号。这个问题太长了,无法在评论中解释,但是您可以在这里找到一些“不要那样做”的例子。 - alex

1
  1. 使用环境变量

在OSX和Linux中,您可以使用export命令设置环境变量。以下是设置SESSION_SECRET键值的示例:

export SESSION_SECRET="keyboard cat"

在Windows中,你可以使用set命令。
set SESSION_SECRET="keyboard cat"

每次运行时,您也可以设置环境变量。

SESSION_SECRET="keyboard cat" node secret-env.js

使用node.js的process.env来在代码中访问环境变量。
var express = require('express')
var session = require('express-session')
var app = express()
app.use(session({secret: process.env.SESSION_SECRET}))
  1. 从命令行请求参数

保护机密信息的最佳方式是不将其存储在设置文件中。 如果使用noopt软件包作为参数从命令行请求配置信息,则无需将秘密信息存在文件中。 以下是使用noopt软件包作为参数请求会话密钥的示例。

var nopt = require("nopt")

var longOpts = {
  "sessionSecret": String,
}

var shortOpts = {
  "s": ["--sessionSecret"],
}

var parsed = nopt(longOpts, shortOpts, process.argv, 2)

console.log("session secret is:", parsed.sessionSecret)

node secret-arg.js --sessionSecret "keyboard cat"
node secret-arg.js -s "keyboard cat"

优点:相比于硬编码或将机密信息作为配置文件,公开机密信息更加安全。

缺点:每次启动应用程序时需要输入的信息量增加,有些麻烦。如果尝试创建和解决脚本,则密码仍然存在于脚本中的问题仍然存在。


1

我发现这是一种不错的处理配置文件的方式,可以考虑到不同的环境:

config.coffee

exports.setEnvironment = (env) ->
    switch env
        when "development"
            exports.DEBUG_LOG = true
            exports.DB_PORT = '27017'
            # ...
        when "testing"
            exports.DEBUG_ERROR = true
            exports.DEBUG_CLIENT = true
            # ...
        when "production"
            exports.DEBUG_LOG = false
            # ...
        else console.log "environment #{env} not found"

server.coffee:

config = require('./config')
config.setEnvironment env

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