NestJs:无法读取模块文件中的env变量,但能够读取服务文件中的env变量?

时间:2019-04-14 08:35:47

标签: javascript node.js typescript nestjs dotenv

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

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

因此在users.service.ts之类的服务文件中,此方法有效:

saveAvatar() {
    const path = process.env.AVATAR_PATH    // returns value from .env
}

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

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

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

5 个答案:

答案 0 :(得分:2)

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

import "dotenv" from dotenv;

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

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

答案 1 :(得分:1)

实例化.env时尚未读入您的JwtModule文件。所以要么早点阅读它在创建嵌套应用或更好的嵌套应用之前,在您的main.ts中:创建一个ConfigService并明确显示对配置的依赖关系:

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

有关如何创建ConfigService的信息,请参见this answer

答案 2 :(得分:1)

您可以将其用作全局模块,以便从其他模块进行访问。

要在其他模块中使用ConfigModule时,您需要 导入它(任何Nest模块的标准配置)。或者, 通过设置选项对象的isGlobal将其声明为全局模块 属性设置为true,如下所示。在这种情况下,您将不需要 将ConfigModule加载到根目录后,将其导入其他模块 模块(例如AppModule)

.https://docs.nestjs.com/techniques/configuration#use-module-globally

ConfigModule.forRoot({
  isGlobal: true
});

您还可以在此处找到如何使用配置服务:https://docs.nestjs.com/techniques/configuration#using-the-configservice

答案 3 :(得分:0)

就像@KimKen所说的那样,问题在于,在实例化JwtModule时,环境变量仍未加载。但是,我对@KimKen的回答有另一种方法,您可能也会对此感兴趣。

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

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

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

然后您的身份验证模块将类似于:

@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
        }
    }

然后,它就像在app.module中一样容易,也可以在加载auth.module的任何地方通过forRoot静态方法将其导入。

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

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

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

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

AuthModule.forRoot(process.env.SECRET)

但是似乎动态模块最后被加载了,所以没有必要。

答案 4 :(得分:0)

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

这有效:

@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 {}

如果没有

@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 {}

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