让前端飞Web前端之路

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

2019-07-21  本文已影响3人  cbw100

大部分不会把资料库连线帐号、密码等相关讯息写在程式码里面,通常写在一个档案里面,程式里面用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变数

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
上一篇下一篇

猜你喜欢

热点阅读