国产gaysexchina男同gay,japanrcep老熟妇乱子伦视频,吃奶呻吟打开双腿做受动态图,成人色网站,国产av一区二区三区最新精品

NestJS 配置

2023-09-08 16:58 更新

應(yīng)用程序通常在不同的環(huán)境中運(yùn)行。根據(jù)環(huán)境的不同,應(yīng)該使用不同的配置設(shè)置。例如,通常本地環(huán)境依賴(lài)于特定的數(shù)據(jù)庫(kù)憑據(jù),僅對(duì)本地 DB 實(shí)例有效。生產(chǎn)環(huán)境將使用一組單獨(dú)的 DB 憑據(jù)。由于配置變量會(huì)更改,所以最佳實(shí)踐是將配置變量存儲(chǔ)在環(huán)境中。

外部定義的環(huán)境變量通過(guò) process.env global 在 Node.js 內(nèi)部可見(jiàn)。 我們可以嘗試通過(guò)在每個(gè)環(huán)境中分別設(shè)置環(huán)境變量來(lái)解決多個(gè)環(huán)境的問(wèn)題。 這會(huì)很快變得難以處理,尤其是在需要輕松模擬或更改這些值的開(kāi)發(fā)和測(cè)試環(huán)境中。

在 Node.js 應(yīng)用程序中,通常使用 .env 文件,其中包含鍵值對(duì),其中每個(gè)鍵代表一個(gè)特定的值,以代表每個(gè)環(huán)境。 在不同的環(huán)境中運(yùn)行應(yīng)用程序僅是交換正確的.env 文件的問(wèn)題。

在 Nest 中使用這種技術(shù)的一個(gè)好方法是創(chuàng)建一個(gè) ConfigModule ,它暴露一個(gè) ConfigService ,根據(jù) $NODE_ENV 環(huán)境變量加載適當(dāng)?shù)?nbsp;.env 文件。雖然您可以選擇自己編寫(xiě)這樣的模塊,但為方便起見(jiàn),Nest 提供了開(kāi)箱即用的@ nestjs/config軟件包。 我們將在本章中介紹該軟件包。

安裝

要開(kāi)始使用它,我們首先安裝所需的依賴(lài)項(xiàng)。

$ npm i --save @nestjs/config

注意 @nestjs/config 內(nèi)部使用 dotenv 實(shí)現(xiàn)。

開(kāi)始使用

安裝完成之后,我們需要導(dǎo)入ConfigModule模塊。通常,我們?cè)诟KAppModule中導(dǎo)入它,并使用.forRoot()靜態(tài)方法導(dǎo)入它的配置。

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';

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

上述代碼將從默認(rèn)位置(項(xiàng)目根目錄)載入并解析一個(gè).env文件,從.env文件和process.env合并環(huán)境變量鍵值對(duì),并將結(jié)果存儲(chǔ)到一個(gè)可以通過(guò)ConfigService訪問(wèn)的私有結(jié)構(gòu)。forRoot()方法注冊(cè)了ConfigService提供者,后者提供了一個(gè)get()方法來(lái)讀取這些解析/合并的配置變量。由于@nestjs/config依賴(lài)dotenv,它使用該包的規(guī)則來(lái)處理沖突的環(huán)境變量名稱(chēng)。當(dāng)一個(gè)鍵同時(shí)作為環(huán)境變量(例如,通過(guò)操作系統(tǒng)終端如export DATABASE_USER=test導(dǎo)出)存在于運(yùn)行環(huán)境中以及.env文件中時(shí),以運(yùn)行環(huán)境變量?jī)?yōu)先。

一個(gè)樣例.env文件看起來(lái)像這樣:

DATABASE_USER=test
DATABASE_PASSWORD=test

自定義 env 文件路徑

默認(rèn)情況下,程序在應(yīng)用程序的根目錄中查找.env文件。 要為.env文件指定另一個(gè)路徑,請(qǐng)配置forRoot()的配置對(duì)象 envFilePath 屬性(可選),如下所示:

ConfigModule.forRoot({
  envFilePath: '.development.env',
});

您還可以像這樣為.env 文件指定多個(gè)路徑:

ConfigModule.forRoot({
  envFilePath: ['.env.development.local', '.env.development'],
});

如果在多個(gè)文件中發(fā)現(xiàn)同一個(gè)變量,則第一個(gè)變量?jī)?yōu)先。

禁止加載環(huán)境變量

如果您不想加載.env 文件,而是想簡(jiǎn)單地從運(yùn)行時(shí)環(huán)境訪問(wèn)環(huán)境變量(如 OS shell 導(dǎo)出,例如export DATABASE_USER = test),則將options對(duì)象的ignoreEnvFile屬性設(shè)置為true,如下所示 :

ConfigModule.forRoot({
  ignoreEnvFile: true,
});

全局使用

當(dāng)您想在其他模塊中使用ConfigModule時(shí),需要將其導(dǎo)入(這是任何 Nest 模塊的標(biāo)準(zhǔn)配置)。 或者,通過(guò)將options對(duì)象的isGlobal屬性設(shè)置為true,將其聲明為全局模塊,如下所示。 在這種情況下,將ConfigModule加載到根模塊(例如AppModule)后,您無(wú)需在其他模塊中導(dǎo)入它。

ConfigModule.forRoot({
  isGlobal: true,
});

自定義配置文件

對(duì)于更復(fù)雜的項(xiàng)目,您可以利用自定義配置文件返回嵌套的配置對(duì)象。 這使您可以按功能對(duì)相關(guān)配置設(shè)置進(jìn)行分組(例如,與數(shù)據(jù)庫(kù)相關(guān)的設(shè)置),并將相關(guān)設(shè)置存儲(chǔ)在單個(gè)文件中,以幫助獨(dú)立管理它們

自定義配置文件導(dǎo)出一個(gè)工廠函數(shù),該函數(shù)返回一個(gè)配置對(duì)象。配置對(duì)象可以是任意嵌套的普通 JavaScript 對(duì)象。process.env對(duì)象將包含完全解析的環(huán)境變量鍵/值對(duì)(具有如上所述的.env文件和已解析和合并的外部定義變量)。因?yàn)槟刂屏朔祷氐呐渲脤?duì)象,所以您可以添加任何必需的邏輯來(lái)將值轉(zhuǎn)換為適當(dāng)?shù)念?lèi)型、設(shè)置默認(rèn)值等等。例如:

// config/configuration.ts
export default () => ({
  port: parseInt(process.env.PORT, 10) || 3000,
  database: {
    host: process.env.DATABASE_HOST,
    port: parseInt(process.env.DATABASE_PORT, 10) || 5432
  }
});

我們使用傳遞給ConfigModule.forRoot()方法的 options 對(duì)象的load屬性來(lái)加載這個(gè)文件:

import configuration from './config/configuration';

@Module({
  imports: [
    ConfigModule.forRoot({
      load: [configuration],
    }),
  ],
})
export class AppModule {}

ConfigModule 注冊(cè)一個(gè) ConfigService ,并將其導(dǎo)出為在其他消費(fèi)模塊中可見(jiàn)。此外,我們使用 useValue 語(yǔ)法(參見(jiàn)自定義提供程序)來(lái)傳遞到 .env 文件的路徑。此路徑將根據(jù) NODE_ENV 環(huán)境變量中包含的實(shí)際執(zhí)行環(huán)境而不同(例如,’開(kāi)發(fā)’、’生產(chǎn)’等)。 > info 注意 分配給load屬性的值是一個(gè)數(shù)組,允許您加載多個(gè)配置文件 (e.g. load: [databaseConfig, authConfig])

使用 ConfigService

現(xiàn)在您可以簡(jiǎn)單地在任何地方注入 ConfigService ,并根據(jù)傳遞的密鑰檢索特定的配置值。 要從 ConfigService 訪問(wèn)環(huán)境變量,我們需要注入它。因此我們首先需要導(dǎo)入該模塊。與任何提供程序一樣,我們需要將其包含模塊ConfigModule導(dǎo)入到將使用它的模塊中(除非您將傳遞給ConfigModule.forRoot()方法的 options 對(duì)象中的isGlobal屬性設(shè)置為true)。 如下所示將其導(dǎo)入功能模塊。

// feature.module.ts
@Module({
  imports: [ConfigModule],
  ...
})

然后我們可以使用標(biāo)準(zhǔn)的構(gòu)造函數(shù)注入:

constructor(private configService: ConfigService) {}

在我們的類(lèi)中使用它:

要從 ConfigService 訪問(wèn)環(huán)境變量,我們需要注入它。因此我們首先需要導(dǎo)入該模塊。

// get an environment variable
const dbUser = this.configService.get<string>('DATABASE_USER');
// get a custom configuration value
const dbHost = this.configService.get<string>('database.host');

如上所示,使用configService.get()方法通過(guò)傳遞變量名來(lái)獲得一個(gè)簡(jiǎn)單的環(huán)境變量。您可以通過(guò)傳遞類(lèi)型來(lái)執(zhí)行 TypeScript 類(lèi)型提示,如上所示(例如,get<string>(…))。get()方法還可以遍歷一個(gè)嵌套的自定義配置對(duì)象(通過(guò)自定義配置文件創(chuàng)建,如上面的第二個(gè)示例所示)。get()方法還接受一個(gè)可選的第二個(gè)參數(shù),該參數(shù)定義一個(gè)默認(rèn)值,當(dāng)鍵不存在時(shí)將返回該值,如下所示:

// use "localhost" when "database.host" is not defined
const dbHost = this.configService.get<string>('database.host', 'localhost');

配置命名空間

ConfigModule模塊允許您定義和加載多個(gè)自定義配置文件,如上面的自定義配置文件所示。您可以使用嵌套的配置對(duì)象來(lái)管理復(fù)雜的配置對(duì)象層次結(jié)構(gòu),如本節(jié)所示?;蛘撸梢允褂胷egisterAs()函數(shù)返回一個(gè)“帶名稱(chēng)空間”的配置對(duì)象,如下所示:

export default registerAs('database', () => ({
  host: process.env.DATABASE_HOST,
  port: process.env.DATABASE_PORT || 5432,
}));

與自定義配置文件一樣,在您的registerAs()工廠函數(shù)內(nèi)部,process.env對(duì)象將包含完全解析的環(huán)境變量鍵/值對(duì)(帶有.env文件和已定義并已合并的外部定義變量)

注意 registerAs 函數(shù)是從 @nestjs/config 包導(dǎo)出的。

使用forRoot()的load方法載入命名空間的配置,和載入自定義配置文件方法相同:

// config/database.config.ts
import databaseConfig from './config/database.config';

@Module({
  imports: [
    ConfigModule.forRoot({
      load: [databaseConfig],
    }),
  ],
})
export class AppModule {}

然后我們可以使用標(biāo)準(zhǔn)的構(gòu)造函數(shù)注入,并在我們的類(lèi)中使用它: 現(xiàn)在,要從數(shù)據(jù)庫(kù)命名空間獲取host的值,請(qǐng)使用符號(hào).。使用'database'作為屬性名稱(chēng)的前綴,該屬性名稱(chēng)對(duì)應(yīng)于命名空間的名稱(chēng)(作為傳遞給registerAs()函數(shù)的第一個(gè)參數(shù))

const dbHost = this.configService.get<string>('database.host');

一個(gè)合理的替代方案是直接注入'database'的命名空間,我們將從強(qiáng)類(lèi)型中獲益:

constructor(
  @Inject(databaseConfig.KEY)
  private dbConfig: ConfigType<typeof databaseConfig>,
) {}

注意 ConfigType 函數(shù)是從 @nestjs/config 包導(dǎo)出的。

部分注冊(cè)

到目前為止,我們已經(jīng)使用forRoot()方法在根模塊(例如,AppModule)中處理了配置文件。也許您有一個(gè)更復(fù)雜的項(xiàng)目結(jié)構(gòu),其中特定于功能的配置文件位于多個(gè)不同的目錄中。與在根模塊中加載所有這些文件不同,@nestjs/config包提供了一個(gè)稱(chēng)為部分注冊(cè)的功能,它只引用與每個(gè)功能模塊相關(guān)聯(lián)的配置文件。使用特性模塊中的forFeature()靜態(tài)方法來(lái)執(zhí)行部分注冊(cè),如下所示:

import databaseConfig from './config/database.config';

@Module({
  imports: [ConfigModule.forFeature(databaseConfig)],
})
export class DatabaseModule {}

您可以選擇將 ConfigModule 聲明為全局模塊,而不是在每個(gè)模塊中導(dǎo)入 ConfigModule。 > info 警告在某些情況下,您可能需要使用onModuleInit()鉤子通過(guò)部分注冊(cè)來(lái)訪問(wèn)加載的屬性,而不是在構(gòu)造函數(shù)中。這是因?yàn)閒orFeature()方法是在模塊初始化期間運(yùn)行的,而模塊初始化的順序是不確定的。如果您以這種方式訪問(wèn)由另一個(gè)模塊在構(gòu)造函數(shù)中加載的值,則配置所依賴(lài)的模塊可能尚未初始化。onModuleInit() 方法只在它所依賴(lài)的所有模塊被初始化之后運(yùn)行,因此這種技術(shù)是安全的

Schema驗(yàn)證

一個(gè)標(biāo)準(zhǔn)實(shí)踐是如果在應(yīng)用啟動(dòng)過(guò)程中未提供需要的環(huán)境變量或它們不滿(mǎn)足特定的驗(yàn)證規(guī)則時(shí)拋出異常。@nestjs/config包讓我們可以使用Joi npm 包來(lái)提供這種類(lèi)型驗(yàn)證。使用 Joi,你可以定義一個(gè)對(duì)象Schema對(duì)象并驗(yàn)證對(duì)應(yīng)的JavaScript對(duì)象。 Install Joi (and its types, for TypeScript users): 安裝 Joi(Typescript 用戶(hù)還需要安裝其類(lèi)型申明)

$ npm install --save @hapi/joi
$ npm install --save-dev @types/hapi__joi

注意 最新版本的“@hapi/joi”要求您運(yùn)行 Node v12 或更高版本。對(duì)于較老版本的 node,請(qǐng)安裝“v16.1.8”。這主要是在“v17.0.2”發(fā)布之后,它會(huì)在構(gòu)建期間導(dǎo)致錯(cuò)誤。更多信息請(qǐng)參考他們的文檔github issue

現(xiàn)在,我們可以定義一個(gè) Joi 驗(yàn)證模式,并通過(guò)forRoot()方法的options對(duì)象的validationSchema屬性傳遞它,如下所示

// app.module.ts
import * as Joi from '@hapi/joi';

@Module({
  imports: [
    ConfigModule.forRoot({
      validationSchema: Joi.object({
        NODE_ENV: Joi.string().valid('development', 'production', 'test', 'provision').default('development'),
        PORT: Joi.number().default(3000),
      }),
    }),
  ],
})
export class AppModule {}

由于我們?yōu)?nbsp;NODE_ENV 和 PORT 設(shè)置了默認(rèn)值,因此如果不在環(huán)境文件中提供這些變量,驗(yàn)證將不會(huì)失敗。然而, 我們需要明確提供 API_AUTH_ENABLED。如果我們的 .env 文件中的變量不是模式( schema )的一部分, 則驗(yàn)證也會(huì)引發(fā)錯(cuò)誤。此外,Joi 還會(huì)嘗試將 env 字符串轉(zhuǎn)換為正確的類(lèi)型。

默認(rèn)情況下,允許使用未知的環(huán)境變量(其鍵不在模式中出現(xiàn)的環(huán)境變量),并且不會(huì)觸發(fā)驗(yàn)證異常。默認(rèn)情況下,將報(bào)告所有驗(yàn)證錯(cuò)誤。您可以通過(guò)通過(guò)forRoot() options 對(duì)象的validationOptions鍵傳遞一個(gè) options 對(duì)象來(lái)更改這些行為。此選項(xiàng)對(duì)象可以包含由 Joi 驗(yàn)證選項(xiàng)提供的任何標(biāo)準(zhǔn)驗(yàn)證選項(xiàng)屬性。例如,要反轉(zhuǎn)上面的兩個(gè)設(shè)置,像這樣傳遞選項(xiàng):

// app.module.ts
import * as Joi from '@hapi/joi';

@Module({
  imports: [
    ConfigModule.forRoot({
      validationSchema: Joi.object({
        NODE_ENV: Joi.string().valid('development', 'production', 'test', 'provision').default('development'),
        PORT: Joi.number().default(3000),
      }),
      validationOptions: {
        allowUnknown: false,
        abortEarly: true,
      },
    }),
  ],
})
export class AppModule {}

@nestjs/config包使用默認(rèn)設(shè)置:

  • allowUnknown:控制是否允許環(huán)境變量中未知的鍵。默認(rèn)為true。
  • abortEarly:如果為true,在遇到第一個(gè)錯(cuò)誤時(shí)就停止驗(yàn)證;如果為false,返回所有錯(cuò)誤。默認(rèn)為false。

注意,一旦您決定傳遞validationOptions對(duì)象,您沒(méi)有顯式傳遞的任何設(shè)置都將默認(rèn)為Joi標(biāo)準(zhǔn)默認(rèn)值(而不是@nestjs/config默認(rèn)值)。例如,如果在自定義validationOptions對(duì)象中保留allowUnknowns未指定,它的Joi默認(rèn)值將為false。因此,在自定義對(duì)象中指定這兩個(gè)設(shè)置可能是最安全的。

自定義 getter 函數(shù)

ConfigService定義了一個(gè)通用的get()方法來(lái)通過(guò)鍵檢索配置值。我們還可以添加getter函數(shù)來(lái)啟用更自然的編碼風(fēng)格:

@Injectable()
export class ApiConfigService {
  constructor(private configService: ConfigService) {}

  get isAuthEnabled(): boolean {
    return this.configService.get('AUTH_ENABLED') === 'true';
  }
}

現(xiàn)在我們可以像下面這樣使用getter函數(shù):

// app.service.ts
@Injectable()
export class AppService {
  constructor(apiConfigService: ApiConfigService) {
    if (apiConfigService.isAuthEnabled) {
      // Authentication is enabled
    }
  }
}

擴(kuò)展變量

@nestjs/config包支持環(huán)境變量擴(kuò)展。使用這種技術(shù),您可以創(chuàng)建嵌套的環(huán)境變量,其中一個(gè)變量在另一個(gè)變量的定義中引用。例如:

APP_URL=mywebsite.com
SUPPORT_EMAIL=support@${APP_URL}

通過(guò)這種構(gòu)造,變量SUPPORT_EMAIL解析為support@mywebsite.com。注意${…}語(yǔ)法來(lái)觸發(fā)解析變量APP_URL在SUPPORT_EMAIL定義中的值。

提示 對(duì)于這個(gè)特性,@nestjs/config 包內(nèi)部使用dotenv-expand實(shí)現(xiàn)。 使用傳遞給ConfigModule的forRoot()方法的 options 對(duì)象中的expandVariables屬性來(lái)啟用環(huán)境變量展開(kāi),如下所示:

// app.module.ts
@Module({
  imports: [
    ConfigModule.forRoot({
      // ...
      expandVariables: true,
    }),
  ],
})
export class AppModule {}

在main.ts中使用

雖然我們的配置是存儲(chǔ)在服務(wù)中的,但它仍然可以在 main.ts 文件中使用。通過(guò)這種方式,您可以使用它來(lái)存儲(chǔ)諸如應(yīng)用程序端口或 CORS 主機(jī)之類(lèi)的變量。

要訪問(wèn)它,您必須使用app.get()方法,然后是服務(wù)引用:

const configService = app.get(ConfigService);

然后你可以像往常一樣使用它,通過(guò)調(diào)用帶有配置鍵的 get 方法:

const port = configService.get('PORT');


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)