阅读 356

NestJS: 动态获取项目配置的几种方法及实现

NestJs中动态获取项目配置(以配置typeorm举例)

NestJs中有多种方式来获取项目配置,如下所示为本文介绍的两种方法(均为真实用例)

  • 通过文件读取项目配置
  • 通过配置中心获取项目配置

一、文件读取项目配置

方法

  • 读取.env文件,通过dotenv.parse方法形成key-value pairs,存在envConfig变量里

实现

  1. 通过命令生成Config模块,并更新如下文件
$ nest g service config
$ nest g module config
复制代码

config.service.ts

import { Injectable, Logger } from '@nestjs/common';
import * as dotenv from 'dotenv';
import * as fs from 'fs';

@Injectable()
export class ConfigService {
    private envConfig: {[key: string]: string};

    constructor(filePath: string) {
        // 读取.env文件,通过dotenv.parse方法形成key-value pairs
        // 存在envConfig变量里
        this.envConfig = dotenv.parse(fs.readFileSync(filePath));
    }

    get(key: string){
        return this.envConfig[key];
    }
}
复制代码

config.module.ts

import { Module } from '@nestjs/common';
import { ConfigService } from './config.service';

@Module({
    providers: [
        {
            provide: ConfigService,
            // 刚刚的ConfigService要传入.env路径及文件名
            useValue: new ConfigService(__dirname + `/../../env/${process.env.NODE_ENV || 'development'}.env`),
        },
    ],
    exports: [ConfigService]
})
export class ConfigModule { }

复制代码
  1. 配置TypeOrm模块

typeorm.service.ts

import { TypeOrmModuleOptions, TypeOrmOptionsFactory } from '@nestjs/typeorm';
import { ConfigService } from './config.service';
import { Injectable } from '@nestjs/common';

@Injectable()
export class TypeOrmConfigService 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: this.configService.get('DB_PORT'),,
            username: this.configService.get('DB_USER'),
            password: this.configService.get('DB_PW'),
            database: this.configService.get('DB_NAME'),
            synchronize: this.configService.get('DB_TYPEORM_SYNC') === 'true',
            logging: this.configService.get('DB_TYPEORM_LOG') === 'true',
            entities: [
                __dirname + '/../**/*.entity{.ts,.js}',
            ],
            timezone: 'UTC'
        };
    }
}
复制代码
  1. 更新App的Module模块

app.module.ts

import { Module, NestModule } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import {TypeOrmModule} from "@nestjs/typeorm";
import { ConfigModule } from './config/config.module';
import { TypeOrmConfigService } from './config/typeorm.service';
import { ConfigService } from './config/config.service';

@Module({
  imports: [TypeOrmModule.forRootAsync({
    imports: [ConfigModule],
    inject: [ConfigService],
    useClass: TypeOrmConfigService,
  }), ConfigModule],
  controllers: [AppController],
  providers: [AppService,TypeOrmConfigService],
})
export class AppModule{

}
复制代码

优势

  • 快速查看项目的配置信息
  • 对某些配置进行相关处理,比如密码处理

缺陷

  • 项目中存在example.env文件,每次部署都要重新编写
  • 暴露项目重要配置信息
  • 更改后重启项目配置生效

二、配置中心获取项目配置

因公司使用Apollo搭建的公共配置中心,所以把数据库的连接信息等相关配置存储在配置中心中,启动时获取环境变量信息

方法

  • 使用node-apollo-client插件获取配置信息,存在envConfig变量里
  • 还有别的apollo的包可以使用,这里不做分析

实现

  1. 添加node-apollo-client插件
$ npm install --save-dev node-apollo-client
or
$ yarn add node-apollo-client
复制代码
  1. 更新Config的Module模块,来获取配置信息

config.module.ts

import { Module } from '@nestjs/common';
import { ConfigService } from './config.service';
import Apollo = require('node-apollo-client/dist');

@Module({
    providers: [
        {
            provide: ConfigService,
            useFactory: async () => {
                const apollo = new Apollo({
                    configServerUrl: 'https://ip:port',
                    appId: 'app-id',
                    cluster: 'default', // [optional] default to `default`
                    namespaces: ['application'],
                    listenOnNotification: true, // [optional] default to true
                    fetchCacheInterval: 5 * 60e3,
                });
                const key = ['DB_HOST','DB_PORT','DB_NAME','DB_USER','DB_PW','DB_TYPEORM_SYNC','DB_TYPEORM_LOG']
                const config = await apollo.fetchConfigs({ keys: key });
                return new ConfigService(config);
            },
        },
    ],
    exports: [ConfigService]
})
export class ConfigModule { }
复制代码
  1. 更新Config的Service模块, 这里依旧存储在envConfig中

config.service.ts

import { Injectable, Logger } from '@nestjs/common';

@Injectable()
export class ConfigService {
    private envConfig: {[key: string]: string};

    constructor(config: any) {
        this.envConfig = config
    }

    get(key: string){
        return this.envConfig[key];
    }
}
复制代码

优势

  • 提升项目配置信息的灵活性,且部分配置可多项目复用
  • 不需要每次部署都写一遍配置
  • 更改配置信息不需要重启项目

缺陷

  • 无法直观的查看数据库配置
  • 每次更新配置都需要到配置中心去发布