NestJS配置模块学习笔记
NestJS配置模块学习笔记
核心知识点
1. @nestjs/config 概述
1.1 什么是 @nestjs/config?
@nestjs/config 是 NestJS 官方提供的配置管理模块,其底层内置了 dotenv 库(周下载量极高),负责解析 .env 文件中的键值对,并将其封装为 NestJS 的服务模块。
@nestjs/config
└── 内置 dotenv(解析 .env 文件)
└── 将键值对挂载到 process.env1.2 课程资料说明
课程资料文件夹中的文件命名规则:
| 文件后缀 | 含义 | 用途 |
|---|---|---|
*-start | 初始代码 | 新学员从该文件开始跟着练习 |
*-end(无后缀) | 最终代码 | 学习完成后对比查看配置问题 |
2. 安装与版本管理
2.1 安装模块
pnpm install @nestjs/config2.2 版本锁定
如果安装的版本大版本号与课程不一致(如当前课程版本为
2.2.x),建议锁定版本号安装,避免兼容性问题:
pnpm install @nestjs/config@22.3 验证安装
安装完成后,在 package.json 中确认依赖已正确添加:
{
"dependencies": {
"@nestjs/config": "^2.2.0"
}
}3. 创建 .env 配置文件
3.1 .env 文件格式
在项目根目录创建 .env 文件,采用**键值对(Key-Value)**形式:
DB=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=1234563.2 注意事项
.env文件应加入.gitignore,避免敏感信息提交到代码仓库- 键名之间不要有空格(
DB=mysql/DB = mysql) - 修改
.env文件后需要重启应用才能生效
4. ConfigModule 注册与使用
4.1 在 AppModule 中全局注册(推荐)
// app.module.ts
import { ConfigModule } from '@nestjs/config';
import { Module } from '@nestjs/common';
@Module({
imports: [
// 全局注册配置模块 推荐
ConfigModule.forRoot({
isGlobal: true, // 关键:设为全局模块
}),
UserModule,
],
})
export class AppModule {}
forRoot():读取根目录下的.env文件并加载配置。
isGlobal: true:将 ConfigModule 标记为全局模块,所有子模块可直接注入使用,无需重复导入。
4.2 在 Controller 中注入使用
// user.controller.ts
import { Controller, Get } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { ConfigEnum } from '../enum/config.enum';
@Controller('user')
export class UserController {
constructor(private configService: ConfigService) {}
@Get()
getUsers() {
// 方式一:直接使用字符串(不推荐)
console.log(this.configService.get('DB'));
// 方式二:使用枚举(推荐)
console.log(this.configService.get(ConfigEnum.DB));
console.log(this.configService.get(ConfigEnum.DB_HOST));
return { users: [] };
}
}5. 跨模块使用配置
5.1 问题:非全局模式下跨模块报错
如果不设置 isGlobal: true,在 UserModule 中直接注入 ConfigService 会报错:
Nest can't resolve dependencies of the UserController (ConfigService, ?).
Please make sure that the argument UserService is available in the UserModule context.原因:ConfigModule 未在 UserModule 中导入,ConfigService 无法被解析。
5.2 非全局模式的解决方案(不推荐)
需要在每个需要使用配置的模块中单独导入:
// user.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { UserController } from './user.controller';
@Module({
imports: [
// 每个模块都要导入 繁琐
ConfigModule.forRoot(),
],
controllers: [UserController],
})
export class UserModule {}5.3 两种方式对比
| 方式 | 代码 | 优点 | 缺点 |
|---|---|---|---|
isGlobal: true | 在 AppModule 设置一次 | 所有模块自动可用,代码简洁 | 全局可见 |
| 逐模块导入 | 在每个模块单独导入 | 作用域可控 | 代码重复,维护成本高 |
推荐:在大多数业务项目中使用
isGlobal: true,因为配置本身就是全局性的。
6. 使用枚举管理配置键名
6.1 为什么使用枚举?
直接使用字符串存在以下风险:
// 硬编码字符串:修改 .env 变量名时容易遗漏
this.configService.get('DB');
// 枚举方式:修改一处即可全局生效
this.configService.get(ConfigEnum.DB);当 .env 文件中的变量名发生变更时(如 DB → DB1),只需修改枚举定义即可,所有引用处自动更新。
6.2 创建配置枚举
// enum/config.enum.ts(或 enums/config.ts)
export enum ConfigEnum {
DB = 'DB',
DB_HOST = 'DB_HOST',
DB_PORT = 'DB_PORT',
DB_USERNAME = 'DB_USERNAME',
DB_PASSWORD = 'DB_PASSWORD',
}6.3 使用枚举
// user.controller.ts
import { ConfigEnum } from '../enum/config.enum';
@Controller('user')
export class UserController {
constructor(private configService: ConfigService) {}
@Get()
getUsers() {
const db = this.configService.get(ConfigEnum.DB); // 'mysql'
const host = this.configService.get(ConfigEnum.DB_HOST); // '127.0.0.1'
return { db, host };
}
}6.4 枚举维护流程
1. 修改 .env 文件中的变量名(如 DB → DB1)
2. 同步修改 ConfigEnum 中的枚举值
3. 所有使用 ConfigEnum 的地方自动生效
4. 重启应用代码实战案例
需求描述
在 NestJS 项目中配置数据库连接信息,使用 @nestjs/config 全局加载 .env 配置,并通过枚举在 Controller 中安全访问。
完整实现
项目结构:
src/
├── app.module.ts # 根模块,全局注册 ConfigModule
├── enum/
│ └── config.enum.ts # 配置键名枚举
├── user/
│ ├── user.module.ts # 用户模块
│ └── user.controller.ts # 用户控制器,注入 ConfigService
├── .env # 环境变量文件
└── main.ts # 入口文件第一步:创建 .env 文件
# .env
DB=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=123456第二步:定义配置枚举
// src/enum/config.enum.ts
export enum ConfigEnum {
DB = 'DB',
DB_HOST = 'DB_HOST',
DB_PORT = 'DB_PORT',
DB_USERNAME = 'DB_USERNAME',
DB_PASSWORD = 'DB_PASSWORD',
}第三步:在 AppModule 中全局注册
// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { UserModule } from './user/user.module';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true, // 全局模块
}),
UserModule,
],
})
export class AppModule {}第四步:在 Controller 中使用
// src/user/user.controller.ts
import { Controller, Get } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { ConfigEnum } from '../enum/config.enum';
@Controller('user')
export class UserController {
constructor(private configService: ConfigService) {}
@Get()
getUsers() {
const dbConfig = {
type: this.configService.get(ConfigEnum.DB),
host: this.configService.get(ConfigEnum.DB_HOST),
port: this.configService.get<number>(ConfigEnum.DB_PORT),
username: this.configService.get(ConfigEnum.DB_USERNAME),
};
console.log('数据库配置:', dbConfig);
return { users: [], dbConfig };
}
}第五步:启动并测试
pnpm start:dev浏览器访问 http://localhost:3000/api/v1/user,终端输出:
数据库配置: {
type: 'mysql',
host: '127.0.0.1',
port: 3306,
username: 'root'
}常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
ConfigService 注入报错 | 未在当前模块导入 ConfigModule | 设置 isGlobal: true 或在对应模块导入 |
修改 .env 后配置未更新 | dotenv 只在启动时加载一次 | 重启应用(Ctrl+C 后重新启动) |
获取到的值为 undefined | .env 中的键名与代码中不一致 | 检查键名拼写,使用枚举避免此类问题 |
| 版本不兼容导致 API 差异 | 安装了不同大版本的包 | 使用 pnpm install @nestjs/config@2 锁定版本 |
| TypeScript 类型提示缺失 | configService.get() 返回 any | 使用泛型 get<number>('DB_PORT') 指定类型 |
学习要点总结
@nestjs/config是 NestJS 官方配置模块,底层使用dotenv解析.env文件ConfigModule.forRoot({ isGlobal: true })将配置设为全局可用,避免每个模块重复导入ConfigService.get()用于读取配置值,支持泛型指定返回类型- 使用枚举管理配置键名,提升代码可维护性,修改时只需改一处
- 修改
.env后必须重启应用,因为dotenv仅在应用启动时加载一次
延伸学习资源
官方文档
后续课程预告
- 配置校验:使用
Joi或class-validator对.env配置进行类型和必填校验 - 多环境配置:
.env.development、.env.production等多文件切换方案 - 命名空间配置:按模块拆分配置文件的进阶用法
最佳实践
- 敏感信息(密码、密钥)绝不提交到 Git 仓库
- 使用
.env.example作为配置模板提交,不含实际值 - 结合枚举 + TypeScript 泛型,实现类型安全的配置读取