全局变量与配置文件
通常我们会将一些项目的配置信息写在一个文件内,然后读入内存并使用。在 express 中使用全局变量有多种方案,我们一起看看有哪些常用的方案
准备工作
拷贝第一节的HelloWorld项目
准备一个Resp.js模块:
js
module.exports = {
Ok: (...args)=>{
return {
code: 200,
msg: args[0]?args[0]:"Ok",
data: args[1]?args[1]:null
}
}
}
global
在global对象中挂载我们需要全局共享的量,比如我们想要挂载一个全局的config作为整个express应用的配置,就在项目的唯一入口文件(如: index.js, app.js等)的最顶上(优先于任何模块)设置一次:
js
// index.js
global.config = {
appname: "GlobalVar"
}
/** 更简洁的写法,隐变量,首次被执行到后,会自动挂载到全局
config = {
appname: "GlobalVar"
}
*/
//创建app应用...
这样我们就可以在其它任何地方调用config,比如新建一个router.js挂载到express应用上去
js
// router.js
const routes = require('express').Router();
routes.get('/global', (req, res, next)=>{
res.send(Resp.Ok("global中的全局变量", {"appname":config.appname}));
});
module.exports = routes;
// index.js
app.use(routes);
如果我们有很多需要全局共享的配置,挤在index.js的上方多少有点不雅观,那我们可以把它们写在一个文件里,然后在index.js最顶上引入一下
js
// global.js
global.config = {
appname: "GlobalVar"
}
// index.js
require('./global');
**注意:**由于global中的变量是可以直接以变量名xxx
调用的,无需global.xxx
,如果变量名设置的比较普通,就比如上面的config
,甚至更简单的a
之类的,很可能跟其它模块中定义的临时变量冲突,造成变量污染,因此在global上挂载变量时取名一定要特殊点,比如:之前的config
替换为__config
js
global.__config = {
appname: "GlobalVar"
}
优点:
- 调用很便捷
缺点:
- 可能变量污染
- 没有代码提示,不心安
module
自定义一个module,存放一些变量,在需要的地方进行引入
比如:我们自建一个config.js
js
// config.js
module.exports = {
appname: "GlobalVar"
}
在router.js中引入config.js
js
// router.js
const CONFIG = require('./config');
routes.get('/module', (req, res, next)=>{
res.send(Resp.Ok("config模块当作全局变量", {"appname":CONFIG.appname}));
});
优点:
- 能有代码提示
- 无变量污染
缺点:
- 每次都要引入,比较麻烦
app.set
在 express 的应用设置表中设置应用内的全局变量:
js
// index.js
app.set("appname", "GlobalVar");
在其它地方调用app,如挂载在app上的router:
js
// router.js
routes.get('/app', (req, res, next)=>{
res.send(Resp.Ok("app中的'全局'变量", {"appname":req.app.get("appname")}));
});
在挂载在app下的子应用中,调用父app中的设置,当某字段在子应用中没有设置时,会继承父应用中的字段
js
//subapp.js
const app = require('express')();
const Resp = require('./Resp');
//当子应用没有设置时,会继承父应用中设置的字段
// app.set('appname', "subapp");
app.all('/', (req, res, next) => {
res.send(Resp.Ok("子应用获取父应用中的全局变量", {
appname: req.app.get("appname")
}));
})
module.exports = app;
//index.js
const subapp = require('./subapp');
app.use('/subapp',subapp);
优点:
- 能有代码提示
process.env
在进程的环境变量中挂载全局变量:
js
//index.js
process.env.appname = "GlobalVar";
在其它地方调用process.env.appname
:
js
// subapp2.js
const app = require('express')();
const Resp = require('./Resp');
app.all('/', (req, res, next) => {
// console.log(app.settings.env);
res.send(Resp.Ok("在process.env上挂载全局变量", {
appname: process.env.appname
}));
})
module.exports = app;
//index.js
const subapp2 = require('./subapp2');
app.use('/process.env',subapp2);
缺点:
- 没有代码提示,不心安
json
以上的方案都是将配置信息写在js文件中的,对于一个正规的项目来说多少有点儿戏,毕竟写在js中的变量是很容易就能被改变的。绝大多数时候,配置信息是需要变化也不允许变化的,我们只需要静态的信息即可。在Js项目中,经常用json文件作为静态配置文件。
新建一个config.json文件:
json
{
"appname": "GlobalVar"
}
在我们的router中新加一条测试一下,不管你在哪里require,在首次被require之后,修改json文件内容将不会再产生影响
JS
routes.get('/json', (req, res, next)=>{
let configJson = require('./config.json');
res.send(Resp.Ok("json静态配置文件", {"appname":configJson.appname}));
});
json文件不支持注释,如果想要注释,要么曲线救国(加与被备注键相关的键值对),要么使用Json5规范
shell
npm install json5
新建一个config.json5文件:
json5
{
"appname": "GlobalVar" //应用名
}
接着在项目的入口文件中引入register,会挂载到全局:
js
require('json5/lib/register');
之后require就可以解析json5
文件了:
js
routes.get('/json5', (req, res, next)=>{
let configJson5 = require('./config.json5');
res.send(Resp.Ok("json5静态配置文件", {"appname":configJson5.appname}));
});
yaml
相比.json
文件,.yaml
(或.yml
)文件是更加现在的配置文件,json文件有着严格的格式要求,yaml(yml)书写起来则更加自然
新建一个config.yaml文件:
yaml
# 应用名
appname: GlobalVar # 应用名
在nodeJs中读取yaml需要借助fs 和js-yaml:
shell
npm install fs
npm install js-yaml
把fs挂载到全局即可(之前的global.js),一般情况下也不会取fs这样的局部变量名,如果需要频繁的操作文件,挂载到全局后会方便很多:
js
global.fs = require('fs');
在router.js中引入js-yaml
并新建一个测试路由:
js
const yaml = require('js-yaml');
routes.get('/yaml', (req, res, next)=>{
/*Object */
let configYaml = yaml.load(fs.readFileSync('./config.yaml'));
res.send(Resp.Ok("yaml动态配置文件", {"appname":configYaml.appname}));
});
由于是通过fs读取yaml文件的,因此在改变yaml文件中的内容后,访问路由的结果也会变
本文总共介绍了6种方案,在项目具体采用哪种并没有绝对的说法,因地制宜即可。