03-nestjs基础实践,生命周期,配置环境配置

121 阅读3分钟

nestjs的生命周期

nestjs的生命周期从上到下的顺序如下

  • 客户端请求
  • 中间件 middleware
    • 全局中间件 -> 模块中间件
  • 守卫 guards
    • 全局守卫 -> 控制器守卫 -> 路由守卫
  • 拦截器 interceptors
    • (pre)全局拦截器 -> (pre)控制器拦截器 -> (pre)路由拦截器
  • 管道 pipes
    • 全局管道 -> 控制器管道 -> 路由管道 -> 路由参数管道
  • 控制器 controllers
  • 服务 providers
  • 拦截器 interceptors
    • (post)路由拦截器 -> (post)控制器拦截器 -> (post)全局拦截器
  • 过滤器 filters
    • 路由过滤器 -> 控制器过滤器 ->全局过滤器
  • 响应回客户端 image.png

node配置环境变量

安装插件: npm i dotenv config cross-env -S

dotenv配置简单环境变量

新建.env文件

TOKEN_SECRET=devTokenSecret
DATA_USERNAME=devDataUsername

编辑index.js文件

require('dotenv').config()
console.log(process.env.TOKEN_SECRET) // devTokenSecret
console.log(process.env.TOKEN_SECRET) // devDataUsername

缺点:只能配置简单的环境变量

config搭配cross-env配置环境变量

cross-env能够在process.env注入一个属性NODE_ENV

编辑./package.json

{
  "scripts": {
    // 开发环境:console.log(process.env.NODE_ENV) 会打印:development
    "dev": "cross-env NODE_ENV=development node ./index.js",  
    // 测试环境:console.log(process.env.NODE_ENV) 会打印:test
    "test": "cross-env NODE_ENV=test node ./index.js",   
    // 生产环境:console.log(process.env.NODE_ENV) 会打印:production
    "prod": "cross-env NODE_ENV=production node ./index.js"   
  },
}

创建config目录,内部创建default.json,development.json,test.json,production.json, 当运行程序的时候

// default.json
{ "token": "", "database": { "host": "localhost", "port": 8080} }
// development.json
{ "token": "dev_token", "database": { "host": "localhost", "port": 8080} }
// test.json
{ "token": "test_token", "database": { "host": "11.111.111.11", "port": 8081} }
// production.json
{ "token": "prod_token", "database": { "host": "11.111.111.11", "port": 8082} }

config插件能够自动读取config下面的json配置文件,把default.json和对应开发模式的配置文件进行合并输出

当你执行了npm run test,config插件会自动合并default.jsontest.json配置

编辑index.js文件

const config = require('config')
const dbConfig = config.get('database')
const token = config.get('token')
console.log(dbConfig, token) 

nest配置环境变量

安装插件:npm i @nestjs/config dotenv cross-env -S

新建配置文件.env

DB_NAME=mysql
DB_PASSWORD=password

app.module.ts中导入全局配置ConfigModule

import { ConfigModule } from '@nestjs/config';
@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true, // 需要配置这个属性才会全局生效
    }),
    UserModule,
  ],
})
export class AppModule {}

在子模块./user/user.controller.ts中使用全局配置ConfigService

全局配置会自动读取.env的内容

import { ConfigService } from '@nestjs/config';

@Controller('user')
export class UserController {
  constructor(
    private configService: ConfigService,
  ) {}
  @Get()
  getUsers() {
    const DB_NAME = this.configService.get('DB_NAME')
    const DB_PASSWORD = this.configService.get('DB_PASSWORD')
    console.log(DB_NAME, DB_PASSWORD); // 输出:mysql password
  }
}

cross-env 配置环境读取不同的内容

package.json的命令中引入cross-env配置不同的环境

"scripts": {
"start:dev": "cross-env NODE_ENV=development nest start --watch",
"start:prod": "cross-env NODE_ENV=production node dist/main",
},

在根目录新增加.env.development.env.production, 修改app.module.tsConfigModule的配置

ConfigModule.forRoot({
  isGlobal: true, // 需要配置这个属性才会全局生效
  + envFilePath: `./.env.${process.env.NODE_ENV}`, // 读取对应环境的配置文件
}),

增加如上配置后, 运行不同的命令会项目会读取对应环境的配置文件. 但是如果需要读取公共配置文件怎么办?

增加公共配置

修改app.module.tsConfigModule的配置

import * as dotenv from 'dotenv';
ConfigModule.forRoot({
  isGlobal: true, // 需要配置这个属性才会全局生效
  envFilePath: `./.env.${process.env.NODE_ENV}`, // 读取对应环境的配置文件
  + load: [() => dotenv.config({ path: '.env' })], // 读取`.env`文件作为公共配置
}),

增加load配置会读取.env文件作为公共配置和对应环境的配置合并

配置文件参数验证

安装插件:npm i joi -S , joi文档

修改app.module.tsConfigModule的配置

import * as Joi from 'joi';
ConfigModule.forRoot({
  isGlobal: true, // 需要配置这个属性才会全局生效
  envFilePath: `./.env.${process.env.NODE_ENV}`, // 读取对应环境的配置文件
  load: [() => dotenv.config({ path: '.env' })], // 读取`.env`文件作为公共配置
  validationSchema: Joi.object({
    DB_NAME: Joi.string().required(),
    DB_PASSWORD: Joi.string().required(),
    DB_PORT: Joi.number().default(3306),
    DB_HOST: Joi.string().required().ip(),
  }),
}),

命令行覆盖环境变量

在启动项目的时候可以灵活配置环境变量:npx cross-env DB_NAME=terminal_dbname npm run start:dev

在这里设置的DB_NAME=terminal_dbname会覆盖项目中的process.env.DB_NAME