美文网首页让前端飞Web前端之路
Nest.js学习之路(27)-存取env变量使用dotenv-

Nest.js学习之路(27)-存取env变量使用dotenv-

作者: cbw100 | 来源:发表于2019-07-21 13:53 被阅读3次

    大部分不会把资料库连线帐号、密码等相关讯息写在程式码里面,通常写在一个档案里面,程式里面用key来读取value,ASP.NET Core里面是写在appsettings.json,透过Configuration存取appsetting.json

    nestjs是采用dotenv套件,使用Config Service存取dotenv下的变数。

    dotenv是透过读取.env档,把key-value pair存到node.js下process.env

    假设把数据库连接的相关讯息存到.dev,文件名可以自行决定,比较多是跟环境有关,比如开发环境就development.env,正式环境就prod.env,未来采用docker或kubernetes可以传入NODE_ENV来切换,取得该环境下的数据库连接信息

    把数据库相关连接信息放到development.env,这个文件应该加入gitignore

    APP_NAME=Geekjc
    
    DB_NAME=demo-nest
    DB_HOST=localhost
    DB_PORT=3306
    DB_USERNAME=mysql
    DB_PW=root
    DB_TYPEORM_SYNC=true
    DB_TYPEORM_LOG=true
    

    使用Config Service可以更方便在各个nestjs module存取process.env,只要注入Config Service。

    新增config.service

    import * as dotenv from 'dotenv';
    import * as fs from 'fs';
    
    import { Injectable } from '@nestjs/common';
    
    @Injectable()
    export class ConfigService {
    
        private readonly envConfig: {[key: string]: string};
    
        constructor(filePath: string) {
            // 读取.env文件,通过dotenv.parse方法形成key-value pairs
            // 存在envConfig变量里
            this.envConfig = dotenv.parse(fs.readFileSync(filePath));
        }
    
        // 传进來key,回传value
        get(key: string){
            return this.envConfig[key];
        }
    
        // 可以写方法处理env变量,这样也比较好除错
        getDbPassword(){
            return this.envConfig.DB_PW;
        }
    
    }
    

    为了在其他的module可以重复利用Config Service(import后注入(inject)),建立config.module.ts

    import { ConfigService } from './config.service';
    import { Module } from '@nestjs/common';
    
    @Module({
        providers: [
            // 这是nestjs另外一种Dependency Injection的方式
            {
                // 如果nestjs IoC Container要ConfigService的时候
                provide: ConfigService,
                // 回传"这个"值
                // 刚刚的ConfigService要传入.env路径及文件名
                useValue: new ConfigService(`${process.env.NODE_ENV || 'development'}.env`),
            },
        ],
        // export表示这个Module被import后,ConfigService可以被其他Module Inject
        exports: [ConfigService],
    })
    export class ConfigModule {}
    

    先import config module到app module并修改app controller测试

    app.module.ts

    @Module({
      imports: [TypeOrmModule.forRoot(), ConfigService, SharedModule, 
      ...
    })
    

    app.controller.ts

    @Controller()
    export class AppController {
      // 注入Config Service
      constructor(private configService: ConfigService){
      }
      @Get()
      getAppIndex(){
        // 用get并传入.env底下APP_NAME这个key
        return this.configService.get('APP_NAME');
      }
    }
    

    使用postman测试


    2018112603.png

    再来要refactor TypeORM载入的数据库连线信息,主要参考官网Database async部分

    有两种做法,都是在typeorm初始化数据库连接之前,要import Config Service取的process.env变数

    • useFactory
      • 指定指定TypeOrmOptions
    • useExisting
      • 另外建立TypeOrmConfigService实作TypeOrmOptionsFactory

    TypeOrmOptions就是数据库连接信息及其他设定如retry、alive time等

    照官网作useFactory不成功,在指定type变量部分,typescript complier会出现型别不符合expoConnectionOption,这个问题要另外找答案

    错误信息如下


    2018112604.png

    而另外建立TypeOrmConfigService来提供forRootAsync所需要的TypeOrmOptions可以测试OK

    建立TypeOrmConfigService

    import { TypeOrmModuleOptions, TypeOrmOptionsFactory } from '@nestjs/typeorm';
    
    import { ConfigService } from './config.service';
    import { DatabaseType } from 'typeorm';
    import { Injectable } from '@nestjs/common';
    
    @Injectable()
    export class TypeOrmConfigService
        // 需要实现TypeOrmOptionsFactory
            implements TypeOrmOptionsFactory {
        // 注入config service取得env变量
        constructor(private readonly configService: ConfigService) {}
        // 就是回传TypeOrmOptions对象
        createTypeOrmOptions(): TypeOrmModuleOptions{
            return {
                        type: 'mysql', // configService.get('DB_TYPE') as DatabaseType,
                        host: this.configService.get('DB_HOST'),
                        port: Number(this.configService.get('DB_PORT')),
                        username: this.configService.get('DB_USERNAME'),
                        password: this.configService.get('DB_PASSWORD'),
                        database: this.configService.get('DB_NAME'),
                        synchronize: this.configService.get('DB_TYPEORM_SYNC') === 'true',
                        logging: this.configService.get('DB_TYPEORM_LOG') === 'true',
                        entities: [
                            'src/shared/entity/*.ts',
                        ],
                        migrations: [
                            'src/shared/migration/**/*.ts',
                        ],
                        subscribers: [
                            'src/shared/subscriber/*.ts',
                        ],
            };
        }
    }
    

    修改在app module typeorm设置

    @Module({
        // 涉及非同步载入Connection Option的时候,改用forRootAsync
      imports: [TypeOrmModule.forRootAsync({
            imports: [ConfigModule],
            inject: [
                // 宣告哪个provider或是service需要被注入
                ConfigService,
            ],
            // 指定用TypeOrmConfigService,作为载入TypeOrmOptions
        // Options就是数据库连接信息等
            useClass: TypeOrmConfigService,
        }), ConfigModule, SharedModule, PlatformModule, RoleModule, AuthModule],
      controllers: [AppController],
        providers: [AppService, TransformResInterceptor],
    })
    

    使用postman测试


    2018112605.png

    推荐一下我的公众号: 【 geekjc 】,微信号: 【 c8706288 】一起学习交流编程知识,分享经验,各种有趣的事。

    tuiguang.png

    相关文章

      网友评论

        本文标题:Nest.js学习之路(27)-存取env变量使用dotenv-

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