前言
hello 我是elk。在之前的文章中,我们已经完成了NestJS项目的基础搭建,集成了Swagger接口文档和Prisma ORM框架。本篇将重点讲解项目中多环境配置方案 和CORS跨域处理的实现,这两个功能对于构建企业级应用至关重要。
环境变量管理
工具选型说明
- @nestjs/config:NestJS官方推荐的配置管理模块,支持.env文件加载和环境变量访问
- cross-env:跨平台环境变量设置工具,解决不同操作系统环境变量设置语法差异问题
- Joi:强大的数据验证库,用于环境变量格式校验
css
pnpm install --save @nestjs/config cross-env joi
注意:
-
最新版本的
Joi
需要 Node.js v12 或更高版本。如果你使用较老版本的 Node.js,请安装v16.1.8
,因为v17.0.2
及更高版本可能在构建过程中出现错误。详情请参阅 Joi Changelog。 -
推荐将
Joi
与官方的@nestjs/config
模块一起使用,以简化配置和验证过程。
创建.env文件
配置文件结构
barh
├── .env # 基础配置
├── .env.development # 开发环境
├── .env.test # 测试环境
└── .env.production # 生产环境
示例.env.development
:
ini
# 数据库配置
DB_TYPE=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=db_demo
DB_USER=root
DB_PASSWORD=root
DB_URL=mysql://root:[email protected]:3306/db_demo
# redis配置
# oss配置
# ...各个配置
脚本配置优化
开头安装了cross-env插件,这个就是用于加载不同的环境配置
在package.json "scripts"中进行配置
json
{
"scripts": {
"build:dev": "cross-env NODE_ENV=development nest build",
"build:pro": "cross-env NODE_ENV=production nest build",
"start": "cross-env NODE_ENV=development nest start",
"start:dev": "cross-env NODE_ENV=development nest start --watch",
"start:debug": "cross-env NODE_ENV=test nest start --debug --watch",
"start:prod": "cross-env NODE_ENV=production node dist/main",
}
}
配置文件目录结构
将配置文件单独分离出来,各配置各的然后统一抛出
barh
├── src
├── config
├── index.ts
└── database.config.ts
└── xxx.config.ts
└── schema.config.ts
示例database.config.ts
typescript
// registerAs-用于注册配置命名空间
import { registerAs } from '@nestjs/config';
/**
* 导出一个默认的函数,用于配置数据库连接选项
* @returns {Object} 包含数据库连接选项的对象
*/
// 定义一个接口,用于描述数据库连接配置
export interface DatabaseConfig {
type: string;
host: string;
port: number;
username: string;
password: string;
database: string;
synchronize: boolean;
logging: boolean;
entities: string[];
migrations: string[];
subscribers: string[];
}
// 导出一个database命名函数,用于配置数据库连接选项
export default registerAs(
'database',
(): DatabaseConfig => ({
// 数据库类型,从环境变量中获取
type: process.env['DB_TYPE'],
// 数据库主机地址,从环境变量中获取
host: process.env['DB_HOST'],
// 数据库端口号,从环境变量中获取
port: Number(process.env['DB_PORT']),
// 数据库用户名,从环境变量中获取
username: process.env['DB_USER'],
// 数据库用户密码,从环境变量中获取
password: process.env['DB_PASSWORD'],
// 要连接的数据库名称,从环境变量中获取
database: process.env['DB_NAME'],
// 是否自动同步数据库结构,设置为 true 时,应用启动时会自动更新数据库结构
synchronize: true,
// 是否启用数据库日志,设置为 false 时,不记录数据库操作日志
logging: false,
// 实体文件的路径,使用通配符匹配所有实体文件
entities: [__dirname + '/../**/*.entity{.ts,.js}'],
// 迁移文件的路径,使用通配符匹配所有迁移文件
migrations: [__dirname + '/migrations/**/*{.ts,.js}'],
// 订阅者列表,这里为空,表示不使用订阅者
subscribers: [],
}),
);
配置校验文件
上面安装了Joi这个插件,就是用于验证环境变量中的格式,我们也统一进行校验
typescript
// schema.config.ts
import * as joi from 'joi';
// 定义配置文件的类型
export interface EnvironmentVariables {
NODE_ENV: 'development' | 'production' | 'staging';
PORT: number;
HOST: string;
DB_TYPE: string;
DB_HOST: string;
DB_PORT: number;
DB_USER: string;
DB_PASSWORD: string;
DB_NAME: string;
any?: any;
}
// 定义配置文件的校验规则
export const configJoiSchema = joi.object({
NODE_ENV: joi.string().valid('development', 'production', 'test').required(),
PORT: joi.number().required().default(3000),
HOST: joi.string().required().default('localhost'),
DB_TYPE: joi.string().required().default('mysql'),
DB_HOST: joi.string().required().default('127.0.0.1'),
DB_PORT: joi.number().required().default(33061),
DB_USER: joi.string().required().default('root'),
DB_PASSWORD: joi.string().required(),
DB_NAME: joi.string().required(),
});
typescript
// index.ts - 统一抛出
import databaseConfig from './database.config';
export default {
databaseConfig,
};
动态配置
typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { SystemModule } from './module/system/system.module';
import { RedisModule } from './module/common/redis/redis.module';
import { LoggerModule } from './module/common/logger/logger.module';
import { ConfigModule } from '@nestjs/config';
// 配置文件
import confg from '@/config/index';
// 配置文件校验
import { configJoiSchema } from '@/config/schema.config';
// 加载环境变量
const envPath = `.env.${process.env.NODE_ENV || 'development'}`;
console.log('🚀 ~ 当前启动的环境:', process.env.NODE_ENV);
@Module({
imports: [
SystemModule,
ConfigModule.forRoot({
// 全局配置
isGlobal: true,
// 环境变量路径
envFilePath: envPath,
// 加载配置文件
load: [...Object.values(confg)],
// 加载校验文件
validationSchema: configJoiSchema,
validationOptions: {
allowUnknown: true,
abortEarly: true,
},
cache: true,
}),
],
})
export class AppModule {}
- allowUnknown:控制是否允许环境变量中的未知键。默认值为
true
- abortEarly:如果为true,则在第一个错误时停止验证;如果为false,则返回所有错误。 默认为false
获取动态配置
通过ConfigService来访问配置文件中的变量
ConfigService是nest/jsconfig提供的一个服务,用来读取环境变量
示例user.service.ts
typescript
import { ConfigService } from '@nestjs/config'
import type { DatabaseConfig } from '@/config/database.config';
export class UserService {
constructor(
private prisma: PrismaService,
private configService: ConfigService,
) {}
getDBConfig() {
const dbHost = this.configService.get<DatabaseConfig>('database').host;
return dbHost;
}
}
CORS配置
跨域资源共享「CORS」是一种允许从另一个域请求资源的机制
开启cors
php
// main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 安全配置建议
app.enableCors({
origin: process.env.CORS_ORIGINS?.split(',') || '*',
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 86400
});
await app.listen(process.env.APP_PORT || 3000);
}
bootstrap();
配置参数说明
参数 | 类型 | 说明 | 生产环境建议值 |
---|---|---|---|
origin | string/string[] | 允许的源 | 指定具体前端域名 |
methods | string[] | 允许的HTTP方法 | 按需开放必要方法 |
allowedHeaders | string[] | 允许的请求头 | 明确指定必要头信息 |
credentials | boolean | 是否允许发送Cookie | 按需开启 |
maxAge | number | 预检请求缓存时间(秒) | 86400(24小时) |
📍 下期预告
《从0搭建NestJS后端服务(四):Redis的集成和配置》
我们将探讨:
- 如何在NestJS中集成Redis
- Redis配置的最佳实践
- 如何利用Redis提升应用性能
- 常见的Redis使用场景和示例
🤝 互动时间
遇到问题?有更好的建议?欢迎留言交流!
- 你在配置多环境时踩过哪些坑?
- 关于跨域配置有什么特别的经验分享?
一起交流成长,让开发更高效!🚀