大部分不会把资料库连线帐号、密码等相关讯息写在程式码里面,通常写在一个档案里面,程式里面用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测试
![](https://img.haomeiwen.com/i1637794/142938d174860101.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,这个问题要另外找答案
错误信息如下
![](https://img.haomeiwen.com/i1637794/a16b4805a43d5dc1.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测试
![](https://img.haomeiwen.com/i1637794/a6bb9d13d0fd7175.png)
推荐一下我的公众号: 【 geekjc 】,微信号: 【 c8706288 】一起学习交流编程知识,分享经验,各种有趣的事。
![](https://img.haomeiwen.com/i1637794/07fef021753c68e0.png)
网友评论