0
点赞
收藏
分享

微信扫一扫

如何利用python 把一个表格某列数据和另外一个表格某列匹配 类似Excel VLOOKUP功能

灯火南山 03-26 07:30 阅读 5

Nestjs配置

应用程序通常在不同的环境中运行,根据环境的不同,应该使用不同的配置设置。例如,通常本地环境依赖于特定的数据库凭据,仅对本地 DB 实例有效,生产环境将使用一组单独的 DB 凭据。

由于配置变量会更改,所以最佳实践是将配置变量存储在环境中。

应用程序通常在不同的环境中运行,根据环境(Development,Production)的不同,应该使用不同的配置设置。

两种方法:

  • 使用@nestjs/config来实现对.envkey=value对进行解析
  • 使用config库解析yaml格式的文件

官方@nestjs/config

最简单的用法

npm i --save @nestjs/config

配置src/app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot(),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

然后创建:.env文件:

DATABASE_USER=test
DATABASE_PASSWORD=test123

下面来使用src/app.controller.ts中使用:

import { Controller, Get } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(
    private readonly appService: AppService,
    private configService: ConfigService,
  ) {}

  @Get()
  getHello(): string {
    const dbUser = this.configService.get<string>('DATABASE_USER');
    console.log(dbUser); // 这里来测试
    return this.appService.getHello();
  }
}

进阶用法

img

从这里点进去,我们发现ConfigModuleOptions

import { ConfigFactory } from './config-factory.interface';
export interface ConfigModuleOptions {
    cache?: boolean;
    isGlobal?: boolean;
    ignoreEnvFile?: boolean;
    ignoreEnvVars?: boolean;
    envFilePath?: string | string[];
    encoding?: string;
    validate?: (config: Record<string, any>) => Record<string, any>;
    validationSchema?: any;
    validationOptions?: Record<string, any>;
    load?: Array<ConfigFactory>;
    expandVariables?: boolean;
}

所支持的参数。

我们可以利用envFilePath配合NODE_ENV来,在不同的启动命令的时候使用不同的配置。

npm i cross-env

然后添加两个文件:.env.development.env.production,比如.env.production

DATABASE_USER=test1
DATABASE_PASSWORD=test123321

下面修改scripts

"start:prod": "cross-env NODE_ENV=production node dist/main",

可以设置app.module.ts中默认是development

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';

const envPath = `.env.${process.env.NODE_ENV || 'development'}`;
console.log('🚀 ~ file: app.module.ts ~ line 7 ~ envPath', envPath);

@Module({
  imports: [
    ConfigModule.forRoot({
      envFilePath: envPath,
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

同样,大家可以启动了测试一下:

npm run start:prod

> nestjs-common-template@0.0.1 start:prod /Users/macos/Projects/nestjs/nestjs-common-template
> cross-env NODE_ENV=production node dist/main

🚀 ~ file: app.module.ts ~ line 7 ~ envPath .env.production

如果需要读取公共的.env文件,则需要使用到ConfigModule.forRootload方法:

  • 安装依赖:

    npm i dotenv
    
  • 修改app.module.ts文件:

    import { Module } from '@nestjs/common';
    import { UserModule } from './user/user.module';
    import { ConfigModule } from '@nestjs/config';
    import * as dotenv from 'dotenv';
    
    const envFilePath = `.env.${process.env.NODE_ENV || `development`}`;
    
    @Module({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          envFilePath,
          // 这里新增.env的文件解析
          load: [() => dotenv.config({ path: '.env' })],
        }),
        UserModule,
      ],
      controllers: [],
      providers: [],
    })
    export class AppModule {}
    
  • 配置.env文件:

    DB=mysql
    DB_HOST=127.0.0.1
    
    DB_URL=www.imooc.com
    

    设置测试:

        const url = this.configService.get('DB_URL');
        console.log(
          '🚀 ~ file: user.controller.ts ~ line 23 ~ UserController ~ getUsers ~ url',
          url,
        );
    
  • 运行测试:

    🚀 ~ file: user.controller.ts ~ line 15 ~ UserController ~ getUsers ~ db mysql-dev 127.0.0.1
    🚀 ~ file: user.controller.ts ~ line 23 ~ UserController ~ getUsers ~ url www.imooc.com
    

解析yaml格式的配置

步骤:

  • 下载js-yaml@types/js-yaml

    npm i js-yaml
    npm i -D @types/js-yaml
    
  • 创建配置:config.yml

    http:
      host: 'localhost'
      port: 8080
    
    db:
      postgres:
        url: 'localhost'
        port: 5432
        database: 'yaml-db'
    
      sqlite:
        database: 'sqlite.db'
    
  • 配置自定义文件configuration.ts

    import { readFileSync } from 'fs';
    import * as yaml from 'js-yaml';
    import { join } from 'path';
    
    const YAML_CONFIG_FILENAME = 'config.yml';
    const filePath = join(__dirname, YAML_CONFIG_FILENAME);
    
    export default () => {
      return yaml.load(readFileSync(filePath, 'utf8'));
    };
    
  • 调用forRoot中的load方法

    import { Module } from '@nestjs/common';
    import { AppController } from './app.controller';
    import { AppService } from './app.service';
    import { ConfigModule } from '@nestjs/config';
    import Configuration from './config/configuration'; // 这里调整
    
    @Module({
      imports: [
        ConfigModule.forRoot({
          load: [Configuration], // load方法
        }),
      ],
      controllers: [AppController],
      providers: [AppService],
    })
    export class AppModule {}
    
  • 修改app.controller.ts中的代码:

    import { Controller, Get } from '@nestjs/common';
    import { ConfigService } from '@nestjs/config';
    import { AppService } from './app.service';
    import { DatabaseConfig } from './interface';
    
    @Controller()
    export class AppController {
      constructor(
        private readonly appService: AppService,
        private configService: ConfigService,
      ) {}
    
      @Get()
      getHello(): string {
        const db = this.configService.get<DatabaseConfig>('db');
        console.log(db);
        return this.appService.getHello();
      }
    }
    
  • 定义src/interface.ts

    export interface DatabaseConfig {
      postgres: PostgresConfig;
      sqlite: SqliteConfig;
    }
    
    export interface PostgresConfig {
      url: string;
      port: number;
      database: string;
    }
    
    export interface SqliteConfig {
      database: string;
    }
    
  • 最后测试:

    {
      postgres: { url: 'localhost', port: 5432, database: 'yaml-db' },
      sqlite: { database: 'sqlite.db' }
    }
    

使用config库解析

步骤:

  • 安装第三方包config

    npm i config -S
    npm i cross-env -D
    
  • 新建 配置文件config/default.json,同样还可以建立development.json, production.json

    {
      "server": {
        "happy": "my default value"
      }
    }
    

    development.json:

    {
      "server": {
        "port": 3001,
        "host": "localhost",
        "username": "test",
        "password": "test"
      }
    }
    

    production.json:

    {
      "server": {
        "port": 3002,
        "host": "localhost",
        "username": "prod",
        "password": "prod"
      }
    }
    

    app.controller.ts中使用:

    import { Controller, Get } from '@nestjs/common';
    import { AppService } from './app.service';
    import * as config from 'config';
    
    @Controller()
    export class AppController {
      constructor(private readonly appService: AppService) {}
    
      @Get()
      getHello(): string {
        const server = config.get('server');
        console.log(server);
        return this.appService.getHello();
      }
    }
    
  • 配置脚本:

    "start:dev": "cross-env NODE_ENV=development nest start --watch",
    "start:prod": "cross-env NODE_ENV=production node dist/main",
    
  • 运行结果:

    npm run start:dev
    {
      happy: 'my default value',
      port: 3001,
      host: 'localhost',
      username: 'test',
      password: 'test'
    }npm run start:prod
    
    > nestjs-common-template@0.0.1 start:prod /Users/macos/Projects/nestjs/nestjs-common-template
    > cross-env NODE_ENV=production node dist/main
    
    {
      happy: 'my default value',
      port: 3002,
      host: 'localhost',
      username: 'prod',
      password: 'prod'
    }
    

配置验证

配置验证,主要是指在应用程序启动时,如果没有提供所需的环境变量或不符合某些验证规则,就会抛出一个异常。@nestjs/config包实现了两种不同的方式来实现这一点。

  • Joi内置验证器。通过Joi,你可以定义一个对象模式,并根据它验证JavaScript对象
  • 一个自定义的validate()函数,它将环境变量作为输入

Joi用法

特别说明:

  • 最新版本的joi需要你运行Node v12或更高版本。旧版本的node请安装v16.1.8。这主要是因为在v17.0.2发布后,在构建的时候会出现错误。更多信息请参考其17.0.0发布说明,点击这里。
  • joi最好配合官方的@nestjs/config进行使用

步骤:

  • 安装依赖

    npm install --save joi
    
  • 定义验证Schema:

    import { Module } from '@nestjs/common';
    import { AppController } from './app.controller';
    import { AppService } from './app.service';
    import * as Joi from 'joi';
    import { ConfigModule } from '@nestjs/config';
    
    const envPath = `.env.${process.env.NODE_ENV || 'development'}`;
    
    @Module({
      imports: [
        ConfigModule.forRoot({
          envFilePath: envPath,
          // 这里多了一个属性:validationSchema
          validationSchema: Joi.object({
            NODE_ENV: Joi.string()
              .valid('development', 'production', 'test', 'provision')
              .default('development'),
            PORT: Joi.number().default(3000),
            DATABASE_USER: Joi.string().required()
          }),
        }),
      ],
      controllers: [AppController],
      providers: [AppService],
    })
    export class AppModule {}
    
    
  • 验证测试

    配置错误脚本:

    "start:dev": "cross-env NODE_ENV=development PORT=toimc nest start --watch",
    

    配置正确的脚本:

    "start:dev": "cross-env NODE_ENV=development PORT=3000 nest start --watch",
    

    测试命令

    npm run start:dev
    

    错误的提示:

    [下午7:33:38] Found 0 errors. Watching for file changes.
    
    /Users/macos/Projects/nestjs/nestjs-common-template/node_modules/_@nestjs_config@0.6.3@@nestjs/config/dist/config.module.js:61
                    throw new Error(`Config validation error: ${error.message}`);
                    ^
    
    Error: Config validation error: "PORT" must be a number
        at Function.forRoot (/Users/macos/Projects/nestjs/nestjs-common-template/node_modules/_@nestjs_config@0.6.3@@nestjs/config/dist/config.module.js:61:23)
        at Object.<anonymous> (/Users/macos/Projects/nestjs/nestjs-common-template/dist/app.module.js:21:35)
        at Module._compile (internal/modules/cjs/loader.js:1063:30)
        at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
        at Module.load (internal/modules/cjs/loader.js:928:32)
        at Function.Module._load (internal/modules/cjs/loader.js:769:14)
        at Module.require (internal/modules/cjs/loader.js:952:19)
        at require (internal/modules/cjs/helpers.js:88:18)
        at Object.<anonymous> (/Users/macos/Projects/nestjs/nestjs-common-template/dist/main.js:4:22)
        at Module._compile (internal/modules/cjs/loader.js:1063:30)
    

    或者修改.env.development中的配置信息:

    DATABASE_USER=
    DATABASE_PASSWORD=test123
    

    错误提示:

    /Users/macos/Projects/nestjs/nestjs-common-template/node_modules/_@nestjs_config@0.6.3@@nestjs/config/dist/config.module.js:61
                    throw new Error(`Config validation error: ${error.message}`);
                    ^
    
    Error: Config validation error: "DATABASE_USER" is not allowed to be empty
        at Function.forRoot (/Users/macos/Projects/nestjs/nestjs-common-template/node_modules/_@nestjs_config@0.6.3@@nestjs/config/dist/config.module.js:61:23)
        at Object.<anonymous> (/Users/macos/Projects/nestjs/nestjs-common-template/dist/app.module.js:21:35)
        at Module._compile (internal/modules/cjs/loader.js:1063:30)
        at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
        at Module.load (internal/modules/cjs/loader.js:928:32)
        at Function.Module._load (internal/modules/cjs/loader.js:769:14)
        at Module.require (internal/modules/cjs/loader.js:952:19)
        at require (internal/modules/cjs/helpers.js:88:18)
        at Object.<anonymous> (/Users/macos/Projects/nestjs/nestjs-common-template/dist/main.js:4:22)
        at Module._compile (internal/modules/cjs/loader.js:1063:30)
    

结论:使用Joi可以很方便对传入应用程序的参数进行验证,可以限制传入的数据类型。

除了上面写的验证以外,还可以加入以下属性来验证输入的命令参数

@Module({
  imports: [
    ConfigModule.forRoot({
      envFilePath: envPath,
      validationSchema: Joi.object({
        NODE_ENV: Joi.string()
          .valid('development', 'production', 'test', 'provision')
          .default('development'),
        PORT: Joi.number().default(3000),
        DATABASE_USER: Joi.string().required()
      }),
      validationOptions: { // 这里加
        allowUnknown: false,
        abortEarly: true,
      },
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

@nestjs/config包使用的默认设置是:

  • allowUnknown:控制是否允许在环境变量中使用未知键。默认为true;
  • abortEarly:如果为true,则在第一个错误时停止验证;如果为false,则返回所有错误。默认值为false;

注意上面的Joi的用法:

  • 主要是校验process.env传入的参数
  • 主要是校验envFilePath初次加载的时候的参数

使用class-validator

步骤:

  • 安装依赖class-validatorclass-transformer

    npm i class-validator class-transformer
    
  • 配置效验文件src/env.validation.ts

    import { plainToClass } from 'class-transformer';
    import { IsEnum, IsNumber, validateSync } from 'class-validator';
    
    enum Environment {
      Development = "development",
      Production = "production"
    }
    
    class EnvironmentVariables {
      @IsEnum(Environment)
      NODE_ENV: Environment;
    
      @IsNumber()
      PORT: number;
    }
    
    export function validate(config: Record<string, unknown>) {
      const validatedConfig = plainToClass(
        EnvironmentVariables,
        config,
        { enableImplicitConversion: true },
      );
      const errors = validateSync(validatedConfig, { skipMissingProperties: false });
    
      if (errors.length > 0) {
        throw new Error(errors.toString());
      }
      return validatedConfig;
    }
    
  • 调整app.module.ts文件

    import { Module } from '@nestjs/common';
    import { AppController } from './app.controller';
    import { AppService } from './app.service';
    import { ConfigModule } from '@nestjs/config';
    import { validate } from './env.validation';
    
    const envPath = `.env.${process.env.NODE_ENV || 'development'}`;
    
    @Module({
      imports: [
        ConfigModule.forRoot({
          envFilePath: envPath,
          validate,
        }),
      ],
      controllers: [AppController],
      providers: [AppService],
    })
    export class AppModule {}
    

与使用Joi验证结果一致。

小结

  • 使用第三方的包config,可以方便的读取配置信息,但是校验却需要在读取的位置来加,对于不需要验证,而需要全局使用的配置项可以使用这种方式;

  • 官方的@nestjs/config可以方便的导入.env的文件,同时结合js-yaml也可以导入yaml格式的配置。

    配置灵活,而且可以配合验证工具Joi进行参数的验证(推荐)

    自定义的校验第三方包class-validator这里只是冰山一角,后面在学习数据验证的时候还会使用到它;

举报

相关推荐

0 条评论