在 Node.js 中可以通過process.env
來訪問當前的環境變量信息,比如:
{ PATH: '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin', TMPDIR: '/var/folders/rs/g4wqpvvj7bj08t35dxvfm0rr0000gn/T/', LOGNAME: 'glen', XPC_FLAGS: '0x0', HOME: '/Users/glen', TERM: 'xterm-256color', COLORFGBG: '7;0', USER: 'glen', ITERM_PROFILE: 'Glen', TERM_PROGRAM: 'iTerm.app', XPC_SERVICE_NAME: '0', SHELL: '/bin/zsh', ITERM_SESSION_ID: 'w0t4p0', PWD: '/Users/glen/work', __CF_USER_TEXT_ENCODING: '0x1F5:0x0:0x0', LC_CTYPE: 'UTF-8', SHLVL: '1', OLDPWD: '/Users/glen/work', ZSH: '/Users/glen/.oh-my-zsh', PAGER: 'less', LESS: '-R', LSCOLORS: 'Gxfxcxdxbxegedabagacad', AUTOJUMP_SOURCED: '1', AUTOJUMP_ERROR_PATH: '/Users/glen/Library/autojump/errors.log', RUST_SRC_PATH: '/Users/glen/work/source/rust/src', _: '/usr/local/bin/node' }
設置環境變量
環境變量的名字一般為大寫,多個單詞之間可通過下划線來連接。
Windows 系統下可通過set
命令來設置環境變量,比如:
$ set HELLO_MSG="Hello, world!"
Linux 系統下可通過export
命令來設置,比如:
$ export HELLO_MSG="Hello, world!"
在 Node.js 中讀取環境變量
創建文件1.js
,代碼如下:
console.log(process.env.HELLO_MSG);
然后在命令行中執行:
$ export HELLO_MSG="Hello, world" && node 1.js
控制台將輸出Hello, world
,即我們啟動程序時給環境變量HELLO_MSG
設置的值。
通過配置文件指定配置
一些規模較小的項目往往會通過單一的配置文件來存儲其配置,比如 CNode 中文社區的開源項目 nodeclub 在啟動時會載入文件config.js
,該文件的大概結構如下:
var config = { // debug 為 true 時,用於本地調試 debug: true, name: 'Nodeclub', // 社區名字 description: 'CNode:Node.js專業中文社區', // 社區的描述 keywords: 'nodejs, node, express, connect, socket.io', // 其他配置項... }; module.exports = config;
在程序啟動的時候,可以使用require()
來載入此文件,得到一個對象,然后通過此對象的屬性來讀取相應的配置信息:
// 載入配置文件 var config = require('./config'); // 以下為使用到配置的部分代碼: if (!config.debug && config.oneapm_key) { require('oneapm'); } app.use(session({ secret: config.session_secret, store: new RedisStore({ port: config.redis_port, host: config.redis_host, }), resave: true, saveUninitialized: true, })) app.listen(config.port, function () { logger.log('NodeClub listening on port', config.port); logger.log('God bless love....'); logger.log('You can debug your app with http://' + config.hostname + ':' + config.port); logger.log(''); });
使用配置文件與使用環境變量來指定配置相比,配置文件的可讀性更強,可以表示一些更復雜的結構,而使用環境變量一般只限於key=value
的形式。但在配置項數量較少時,使用環境變量會更簡單,比如項目中只需要配置一個監聽端口,可以簡單使用export PORT=3000 && node app.js
命令來啟動程序,而不需要單獨創建一個配置文件。大多數時候往往會結合這兩種方式來進行,下文講詳細講解。
其他配置文件格式
一般為了方便,在 Node.js 項目中會習慣使用.js
文件格式,它的好處是可以使用通過程序來動態生成一些配置項,比如 nodeclub 的其中一個配置項:
var config = { // 文件上傳配置 // 注:如果填寫 qn_access,則會上傳到 7牛,以下配置無效 upload: { path: path.join(__dirname, 'public/upload/'), url: '/public/upload/' }, }
其中使用到了path.join()
和__dirname
來生成upload.path
。
JSON格式
另外,我們也可以使用 JSON 格式的配置文件,比如文件config.json
:
{ "debug": true, "name": "Nodeclub", "description": "CNode:Node.js專業中文社區", "keywords": "nodejs, node, express, connect, socket.io" }
在程序中可以通過以下方式來載入JSON文件配置:
// 通過require()函數 var config = require('./config.json'); // 讀取文件並使用JSON.parse()解析 var fs = require('fs'); var config = JSON.parse(fs.readFileSync('./config.json').toString());
大多數時候,我們往往需要添加一些備注信息來說明某個配置項的使用方法及用途,在標准JSON文件中是不允許添加備注的,我們可以使用strip-json-comments
模塊來去掉配置文件中的備注,再將其當作標准的JSON來解析。
比如以下是帶備注信息的JSON配置文件:
{ // debug 為 true 時,用於本地調試 "debug": true, // 社區名字 "name": "Nodeclub", // 社區的描述 "description": "CNode:Node.js專業中文社區", "keywords": "nodejs, node, express, connect, socket.io" }
我們可以編寫一個loadJSONFile()
函數來載入帶有備注的JSON文件:
var fs = require('fs'); var stripJsonComments = require('strip-json-comments'); function loadJSONFile (file) { var json = fs.readFileSync(file).toString(); return JSON.parse(stripJsonComments(json)); } var config = loadJSONFile('./config.json'); console.log(config);
YAML格式
YAML 是面向所有編程語言的對人類友好的數據序列化標准。其最大的優點是可讀性較好,比如以下 YAML 格式的配置:
name: John Smith age: 37 spouse: name: Jane Smith age: 25 children: - name: Jimmy Smith age: 15 - name: Jenny Smith age: 12
其對應的JSON結構如下:
{ "age": 37, "spouse": { "age": 25, "name": "Jane Smith" }, "name": "John Smith", "children": [ { "age": 15, "name": "Jimmy Smith" }, { "age": 12, "name": "Jenny Smith" } ] }
在 Node.js 中可以通過yamljs
模塊來解析 YAML 格式,比如可以編寫一個loadYAMLFile()
函數來載入 YAML 格式的配置文件:
var fs = require('fs'); var YAML = require('yamljs'); function loadYAMLFile (file) { return YAML.parse(fs.readFileSync(file).toString()); } var config = loadYAMLFile('./config.yaml'); console.log(config);
根據運行環境選擇不同的配置
大多數情況下,程序在本地開發環境和生產環境中的配置信息是不一樣的,比如開發時連接到的數據庫里面的數據是模擬出來的,而生產環境要連接到實際的數據庫上,因此我們需要讓程序能根據不同的運行環境來載入不同的配置文件。
使用單一配置文件名
以 nodeclub 項目為例,其載入的配置文件名為./config.js
,項目中有一個默認配置文件./config.default.js
。要運行程序,首先需要復制一份默認配置文件,並保存為./config.js
,再根據當前運行環境來修改./config.js
。
由於./config.js
文件已經被添加到.gitignore
文件中,因此我們./config.js
文件的修改不會被納入到項目的版本管理中,所以不同機器中的./config.js
不會產生沖突,可以使用各自的配置來啟動程序。
通過環境變量指定配置文件名
我們可以通過環境變量來指定配置文件,比如:
$ export CONFIG_FILE="./config/production.js"
然后可以通過以下方式來載入配置文件:
var path = require('path'); var config = require(path.resolve(process.env.CONFIG_FILE));
另外,也可以通過環境變量來指定當前運行環境的名稱,然后在指定目錄下載入相應的配置,比如:
$ export NODE_ENV="production"
然后可以通過以下方式來載入配置文件:
var path = require('path'); var configFile = path.resolve('./config', process.env.NODE_ENV + '.js'); var config = require(configFile);
使用 config 模塊來讀取配置
config 模塊是 NPM 上下載量最高的 Node.js 配置文件管理模塊,其實現原理與上文中介紹的方法大同小異,在實際開發中我們可以考慮使用這個現成的模塊。下面將介紹此模塊的簡單使用方法。
config
模塊通過環境變量NODE_CONFIG_DIR
來指定配置文件所在的目錄,默認為./config
(即當前運行目錄下的config
目錄),通過環境變量NODE_ENV
來指定當前的運行環境版本。
配置文件使用 JSON 格式,模塊加載后,會首先載入默認的配置文件${NODE_CONFIG_DIR}/default.json
,再載入文件${NODE_CONFIG_DIR}/${NODE_ENV}.json
,如果配置項有沖突則覆蓋默認的配置。
比如我們新建默認配置文件config/default.json
:
{ // Customer module configs "Customer": { "dbConfig": { "host": "localhost", "port": 5984, "dbName": "customers" }, "credit": { "initialLimit": 100, // Set low for development "initialDays": 1 } } }
再新建production
環境配置文件config/production.json
:
{ "Customer": { "dbConfig": { "host": "prod-db-server" }, "credit": { "initialDays": 30 } } }
再新建測試文件1.js
:
var config = require('config'); console.log(config);
執行程序,可看到其輸出的結果為默認的配置:
{ Customer: { dbConfig: { host: 'localhost', port: 5984, dbName: 'customers' }, credit: { initialLimit: 100, initialDays: 1 } } }
假如要使用production
的配置,則使用以下命令啟動:
$ export NODE_ENV=production && node 1.js
則其輸出將是如下結果:
{ Customer: { dbConfig: { host: 'prod-db-server', port: 5984, dbName: 'customers' }, credit: { initialLimit: 100, initialDays: 30 } } }
在production.json
文件中,重新定義了Customer.dbConfig.host
和Customer.credit.initialDays
這兩個配置項,所以在production
環境中僅這兩項被覆蓋為新的值,而其他配置項則使用default.json
中指定的值。
載入config
模塊后,其返回的對象實際上就是當前的配置信息,同時提供了兩個方法get()
和has()
來操作配置項。比如:
var config = require('config'); console.log(config); console.log(config.get('Customer')); console.log(config.get('Customer.dbConfig')); console.log(config.has('Customer.dbConfig.host')); console.log(config.has('Customer.dbConfig.host2'));
執行程序后輸出結果如下:
{ Customer: { dbConfig: { host: 'localhost', port: 5984, dbName: 'customers' }, credit: { initialLimit: 100, initialDays: 1 } } } { dbConfig: { host: 'localhost', port: 5984, dbName: 'customers' }, credit: { initialLimit: 100, initialDays: 1 } } { host: 'localhost', port: 5984, dbName: 'customers' } true false
其中get()
用來獲取指定配置,可以使用諸如Customer.dbConfig
這樣的格式,如果配置項不存在則會拋出異常。has()
用來檢測指定配置項是否存在,如果存在則返回true
。
關於config
模塊的詳細使用方法可閱讀其幫助文檔。
參考文獻
- 百度百科:環境變量 - http://baike.baidu.com/view/95930.htm
- ENV 定制開發,測試,發布環境變量 - http://yijiebuyi.com/blog/1bfcf43248a873b39a3471901e764b68.html
- node-config 模塊根據 ENV 環境變量不同加載響應的配置文件 - http://yijiebuyi.com/blog/ad84da0f2d945dd77cf9631c8548e02c.html
- YAML 格式 - http://aicode.cc/article/413.html
- .gitignore 文件使用說明 - http://segmentfault.com/a/1190000000522997
相關模塊
- strip-json-comments - 去掉JSON字符串中的備注 - https://www.npmjs.com/package/strip-json-comments
- yamljs - 解析YAML - https://www.npmjs.com/package/yamljs
- config - 配置文件管理 - https://www.npmjs.com/package/config
原文鏈接:http://morning.work/page/2015-09/nodejs_project_config_loader.html 轉載請注明出處