美文网首页
从零开始的Koa实战(5) 环境配置

从零开始的Koa实战(5) 环境配置

作者: moyufed | 来源:发表于2020-06-24 19:00 被阅读0次

    在项目开发中,我们希望有多个环境配置,如开发环境、生产环境、测试环境等。不同的环境可能需要不同的配置,如数据库、日志、端口等。此外,不同的开发者也有不同的设置。

    经过前面的实战,我们已经有了下面的目录结构:

    koa-blog
    ├── app
    │   ├── middleware
    │   │   └── logger.js
    │   ├── router
    │   │   ├── home.js
    │   │   └── index.js
    │   ├── util
    │   │   └── log_format.js
    │   └── view
    │       ├── 404.html
    │       └── index.html
    ├── app.js
    ├── config
    │   └── config.js
    └── package.json
    

    为了让项目支持不同的开发环境配置,我们将使用以下两个包:

    • config - 用来管理不同的运行环境
    • dotenv-safe - 用来定义一些需要保密的环境变量。

    安装

    $ npm install config dotenv-safe --save
    

    配置运行环境

    config 会默认去查看项目根目录的 config 文件夹,所以需要创建一个 config 目录,这个在之前的实战已经做了。

    接着,来创建一个默认的配置文件 default.json ,其中包含了我们的数据库设置以及服务的启动设置。以本项目为例,配置如下:

    // config/default.json
    
    {
        "App": {
            "ip": "0.0.0.0", // 所有ip可以访问
            "port": 3000 // 端口
        },
        "Router": {
            "apiPrefix": "/api" // 路由前缀
        },
        "Database": {
            "user": "moyufed", // MongoDB用户名
            "password": "123456", // MongoDB密码
            "host": "127.0.0.1",
            "dbName": "koaBlog", // MongoDB数据库名
            "port": 3001
        },
        "Log4js": {
            "appenders": {
                "error": {
                    "category": "errorLogger", //logger名称
                    "type": "dateFile", //日志类型
                    "filename": "logs/error/error", //日志输出位置
                    "alwaysIncludePattern": true, //是否总是有后缀名
                    "pattern": "yyyy-MM-dd-hh.log" //后缀,每小时创建一个新的日志文件
                },
                "response": {
                    "category": "resLogger",
                    "type": "dateFile",
                    "filename": "logs/response/response",
                    "alwaysIncludePattern": true,
                    "pattern": "yyyy-MM-dd-hh.log"
                }
            },
            "categories": {
                "error": {
                    "appenders": [
                        "error"
                    ],
                    "level": "error"
                },
                "response": {
                    "appenders": [
                        "response"
                    ],
                    "level": "info"
                },
                "default": {
                    "appenders": [
                        "response"
                    ],
                    "level": "info"
                }
            }
        }
    }
    

    代码里面的配置包括了 config/config.js 里面的所有配置信息。

    使用运行环境

    在前面的代码中配置了应用的设置 App 以及数据库连接配置 Database,在项目的任何地方需要使用这些配置时,只需要引用 config 就可以了,如:

    // app.js
    
    const Koa = require('koa');
    const config = require('config'); // 引入config
    const appConfig = config.get('App'); // 直接使用 config 获取App的配置
    const apiPrefix = config.get('Router.apiPrefix'); // 可以通过Router.apiPrefix获取具体的值
    console.log(appConfig); // 输出获取的 appConfig
    
    // ...
    
    app.listen(appConfig.port, appConfig.ip, () => {
        console.log(`服务已经启动,访问:http://localhost:${appConfig.port}${apiPrefix}`);
    });
    
    

    router 里面也可以使用config:

    // app/router/index.js
    
    const Router = require('koa-router');
    const config = require('config'); // 引入config
    const apiPrefix = config.get('Router.apiPrefix');
    const router = new Router();
    router.prefix(apiPrefix); // 设置路由前缀
    const home = require('./home');
    
    const index = async (ctx, next) => {
        await ctx.render('index', {title: 'Index', link: 'home'});
    };
    
    router.get('/', index);
    router.get('/index', index);
    router.use('/home', home.routes(), home.allowedMethods()); // 设置home的路由
    
    module.exports = router;
    

    当然,我们可以移除之前创建的 config/config.js 文件,接着来对 log 配置部分进行完善:

    // app/util/log_format.js
    
    const log4js = require('log4js');
    
    + const config = require('config'); // 引入config
    + const log4jsConfig= config.get('Log4js');
    + log4js.configure(log4jsConfig);
    - const { LOG_CONFIG } = require('../../config/config'); //加载配置文件
    - log4js.configure(LOG_CONFIG);
    
    let logFormat = {};
    
    let errorLogger = log4js.getLogger('error'); // categories的元素
    let resLogger = log4js.getLogger('response');
    
    // ...
    
    module.exports = logFormat;
    

    启动服务之后,我们就能看到命令行能够打印出 config.json 里面的 App 配置信息:

    { server: '0.0.0.0', port: 3000 }
    服务已经启动,访问:http://localhost:3000/api
    

    配置多个环境

    经过上面的介绍,我们已经通过 config 来配置运行环境了,但仅是这样并不能实现多个环境的配置,我们需要再配置一个新的环境。

    接下来,配置一个生产环境(production),需要在 config 目录新建一个 production.json 文件:

    // config/production.json
    
    {
        "App": {
            "port": 8000
        }
    }
    

    这里并没有配置所有的变量,而是希望一些变量保持和默认配置一样,如服务启动的地址、数据库名称等等。

    为了验证配置是否生效,需要切换到 production 环境:

    'export NODE_ENV=production' // Linux
    'set NODE_ENV=production' // Windows
    

    同样,为了方便,可以将该命令添加到 package.json 里面:

    {
      "name": "koa-blog",
      "scripts": {
        "start": "node app.js",
        "prod": "set NODE_ENV=production&&npm start"
      },
      // ...
    }
    

    接下来执行命令 npm run prod 启动服务就能够看到输出的环境配置已经改变,端口变成了 8000 。访问 http://localhost:8000/api ,浏览器正常显示页面。

    $ npm run prod
    
    > set NODE_ENV=production&&npm start
    > node app.js
    
    { ip: '0.0.0.0', port: 8000 }
    服务已经启动,访问:http://localhost:8000/api
    

    事实上,当调用 config.get('App') 时,会从对应环境的 json 文件去取值替换 default.json 对应的值。若需要支持更多的运行环境,我们只需要新增其它的文件就行,如 staging.jsonqa.json 等。

    配置环境变量

    大家已经注意到,在前面的配置中,数据库密码是写在 config 里面的,为了安全起见,我们希望把密码配置在本地而不是提交到代码库或者仓库。因此,我们需要用到 dotenv-safe

    dotenv-safe 可以定义私有的变量,这是 node 进程运行时的变量而不是前面配置的环境变量。dotenv-safe 默认会从项目根目录的 .env 文件中加载配置,下面来看看具体操作。

    在根目录新建一个 .env 文件,内容如下:

    DB_PASSWORD=123456
    

    上面代码把数据库密码抽离了出来,并且我们会在 .gitignore 文件中忽略掉这个文件:

    node_modules/
    .idea/
    logs/
    + .env
    

    这样就不会提交到仓库了。

    接下来我们新建一个 .env.example 文件用来提交到代码库,这个文件没有对变量进行赋值,但是能够表明项目使用的配置,注意一来,其他开发者可以根据这里面的内容设置自己的项目环境。如果这个文件里面定义了 .env 没有的值,程序将停止执行。 .env.example 的内容:

    DB_PASSWORD=
    

    然后在 app.js 里面优先引入来进行使用:

    + require('dotenv-safe').config(); // 只需要引入一次
    const Koa = require('koa');
    const config = require('config'); // 引入config
    const appConfig = config.get('App'); // 直接使用 config 获取App的配置
    const apiPrefix = config.get('Router.apiPrefix'); // 可以通过Router.apiPrefix获取具体的值
    + console.log(process.env.DB_PASSWORD); // 123456
    console.log(appConfig); // 输出获取的 appConfig
    
    // ...
    

    启动服务查看输出:

    123456
    { ip: '0.0.0.0', port: 8000 }
    服务已经启动,访问:http://localhost:8000/api
    

    使用.env环境变量

    接下来,我们将使用定义好的变量来替换 config 里面的配置。我们在 config 目录新增一个文件 custom-environment-variables.json

    {
        "Database": {
            "password": "DB_PASSWORD"
        }
    }
    

    这个 json 文件里面我们对数据库的密码进行了定义,当执行 config.get('Database.password') 时, config 将去查询一个叫 “DB_PASSWORD” 的环境变量。如果查询不到就会使用匹配当前 node 环境的 json 文件的值,如果当前 node 环境的值任然没有设置,就会去查询 default.json 里面设置的默认值 。

    验证 app.js 验证是否有效:

    require('dotenv-safe').config(); // 只需要引入一次
    const Koa = require('koa');
    const config = require('config'); // 引入config
    const appConfig = config.get('App'); // 直接使用 config 获取App的配置
    const apiPrefix = config.get('Router.apiPrefix'); // 可以通过Router.apiPrefix获取具体的值
    + const dbConfig = config.get('Database');
    + console.log(dbConfig);
    console.log(process.env.DB_PASSWORD); // 123456
    console.log(appConfig); // 输出获取的 appConfig
    
    // ...
    

    修改 .env 里面的值来启动服务查看是否生效:

    DB_PASSWORD=12345678
    

    结果:

    { user: 'moyufed',
      password: '12345678',
      host: '127.0.0.1',
      dbName: 'koaBlog',
      port: 3001 }
    12345678
    { ip: '0.0.0.0', port: 8000 }
    服务已经启动,访问:http://localhost:8000/api
    

    我们可以看到,数据库的连接密码已经被 .env 修改为 12345678 。通过这种方式,可以将服务器的一些配置抽离到 .env 文件:

    // .env
    APP_IP=0.0.0.0
    APP_PORT=3000
    DB_PASSWORD=123456
    DB_HOST=127.0.0.1
    DB_PORT=3001
    DB_USER=moyufed
    DB_NAME=koaBlog
    
    // .env.example
    APP_IP=
    APP_PORT=
    DB_PASSWORD=
    DB_HOST=
    DB_PORT=
    DB_USER=
    DB_NAME=
    
    // config/custom-environment-variables.json
    {
        "App": {
            "ip": "APP_IP", // 所有ip可以访问
            "port": "APP_PORT" // 端口
        },
        "Database": {
            "user": "DB_USER", // MongoDB用户名
            "password": "DB_PASSWORD", // MongoDB密码
            "host": "DB_HOST",
            "dbName": "DB_NAME", // MongoDB数据库名
            "port": "DB_PORT"
        }
    }
    

    移除引入的旧的config设置

    参考资料:Maintain Multiple Environment Configurations and Secrets in Node.js Apps

    经过本节实战,我们已经完成了项目的环境配置,我们的项目目录如下:

    koa-blog
    ├── .env.example
    ├── .env
    ├── .gitignore
    ├── app
    │   ├── middleware
    │   │   └── logger.js
    │   ├── router
    │   │   ├── home.js
    │   │   └── index.js
    │   ├── util
    │   │   └── log_format.js
    │   └── view
    │       ├── 404.html
    │       └── index.html
    ├── app.js
    ├── config
    │   ├── custom-environment-variables.json
    │   ├── default.json
    │   └── production.json
    ├── package.json
    └── README.md
    

    下一步,我们来使用 mongoose 操作 MongoDB 插入一条数据,并且使用MVC(Model View Controller)规范进行开发…

    相关文章

      网友评论

          本文标题:从零开始的Koa实战(5) 环境配置

          本文链接:https://www.haomeiwen.com/subject/cehdfktx.html