NestJs:无法读取模块文件中的环境变量但可以读取服务文件?

Car*_*ven 12 javascript node.js typescript nestjs dotenv

我的.envNestJs 项目的根目录中有一个文件,其中包含一些 env 变量。

奇怪的是,我能够读取服务文件中的变量,但不能读取模块文件中的变量。

所以在像这样的服务文件中users.service.ts,这有效:

saveAvatar() {
    const path = process.env.AVATAR_PATH    // returns value from .env
}
Run Code Online (Sandbox Code Playgroud)

但是,当访问模块文件中的路径时,如auth.module.ts,这将返回一个空值:

@Module({
    imports: [
       JwtModule.register({
          secretOrPrivateKey: process.env.SECRET   // process.env.SECRET returns an empty string
       })
    ]
})
Run Code Online (Sandbox Code Playgroud)

为什么呢?如何.env在 NestJs 中可靠地访问文件中的环境变量?

Kim*_*ern 18

您的.env文件还没有看过,当你在JwtModule被实例化。因此,要么在main.ts创建 nest 应用程序之前先阅读它,要么在您创建 nest 应用程序之前阅读它,或者更好:创建一个ConfigService并明确对您的配置的依赖:

JwtModule.registerAsync({
    imports: [ConfigModule],
    useFactory: async (configService: ConfigService) => ({
      secretOrPrivateKey: configService.jwtSecret,
    }),
    inject: [ConfigService],
}),
Run Code Online (Sandbox Code Playgroud)

这个答案就如何创建ConfigService


hug*_*anc 9

声明顺序在您的用例中很重要。

这有效:

@Module({
  imports: [
    ConfigModule.forRoot(),
    ScheduleModule.forRoot(),
    TypeOrmModule.forRoot({
      type: 'mongodb',
      host: process.env.SYN_MONGO_HOST,
      port: +process.env.SYN_MONGO_PORT,
      username: process.env.SYN_MONGO_USERNAME,
      password: process.env.SYN_MONGO_PASSWORD,
      database: process.env.SYN_MONGO_DATABASE,
      authSource: 'admin',
      autoLoadEntities: true,
    }),
  ],
  controllers: [],
  providers: [],
})
export class ConfigurationModule {}
Run Code Online (Sandbox Code Playgroud)

当这不

@Module({
  imports: [
    ScheduleModule.forRoot(),
    TypeOrmModule.forRoot({
      type: 'mongodb',
      host: process.env.SYN_MONGO_HOST,
      port: +process.env.SYN_MONGO_PORT,
      username: process.env.SYN_MONGO_USERNAME,
      password: process.env.SYN_MONGO_PASSWORD,
      database: process.env.SYN_MONGO_DATABASE,
      authSource: 'admin',
      autoLoadEntities: true,
    }),
    ConfigModule.forRoot(),
  ],
  controllers: [],
  providers: [],
})
export class ConfigurationModule {}
Run Code Online (Sandbox Code Playgroud)

这是因为 ConfigModule 是在 TypeOrmModule 之前或之后加载的。


小智 6

我刚刚意识到我也解决了我的问题,只需导入 dotenv 并在我的模块(auth.module.ts)开头调用方法配置。

import dotenv from "dotenv";

dotenv.config({path:<path-to-env-file>})

Run Code Online (Sandbox Code Playgroud)

如果您使用项目根目录下的默认 .env 文件,则无需指定路径。


小智 5

就像@KimKen所说,问题是,在实例化 JwtModule 时,环境变量仍然没有加载。不过,我对 @KimKen 的答案有不同的方法,您可能也会感兴趣。

首先,NestJS 提供了一个加载环境变量的 ConfigModule,因此您不需要创建一个,除非您希望以与平常不同的方式处理它。(https://docs.nestjs.com/techniques/configuration

现在,为了解决这个问题,我使模块(auth.module.ts)动态化。简而言之,动态模块是接收参数的模块,它依赖于输入参数来进行正确的实例化。(https://docs.nestjs.com/fundamentals/dynamic-modules

这里真正发生的事情是 JwtModule 也是一个动态模块,因为它依赖于一个变量来进行正确的实例化。因此,这导致您的模块也依赖于其正确实例化的参数,因此使其动态!:)。

那么你的 auth.module 将是这样的:

@Module({})
export class AuthModule {

    static forRoot(): DynamicModule {
        return {
            imports: [
                JwtModule.register({
                    secretOrPrivateKey: process.env.SECRET   // process.env.SECRET will return the proper value
                })
            ],
            module: AuthModule
        }
    }

Run Code Online (Sandbox Code Playgroud)

然后它将像在 app.module 中一样简单,或者在加载 auth.module 的任何位置通过 forRoot 静态方法导入它。

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

@Module({
    imports: [ConfigModule.forRoot(), AuthModule.forRoot()]
})

Run Code Online (Sandbox Code Playgroud)

注意:我建议在 app.module.ts 中导入一次 ConfigModule

PD:您可以使动态 auth.module 在 forRoot 方法中接收参数,并在 app.module 中传递环境变量process.env.SECRET

AuthModule.forRoot(process.env.SECRET)
Run Code Online (Sandbox Code Playgroud)

但似乎动态模块是最后加载的,因此不需要这样做。