process.env 未定义 - NestJS

process.env's are undefined - NestJS

我决定在这里写,因为我 运行 没有想法。我有一个 NestJS 应用程序,我在其中使用了 env - 没有什么不寻常的。但是当我想使用它们时,st运行ge 发生了。我也有自己的这些值的解析器,returns 它们在一个方便的对象中 - 这是第一个文件:

env.ts

const parseStringEnv = (name: string) => {
  const value: string = process.env[name];

  if (!value) {
    throw new Error(`Invalid env ${name}`);
  }

  return value;
};

const parseIntEnv = (name: string) => {
  const value: string = process.env[name];

  const int: number = parseInt(value);

  if (isNaN(int)) {
    throw new Error(`Invalid env ${name}`);
  }

  return int;
};

const parseBoolEnv = (name: string) => {
  const value: string = process.env[name];

  if (value === "false") {
    return false;
  }

  if (value === "true") {
    return true;
  }

  throw new Error(`Invalid env ${name}`);
};

const parseMongoString = (): string => {
  const host = parseStringEnv("DATABASE_HOST");
  const port = parseStringEnv("DATABASE_PORT");
  const user = parseStringEnv("DATABASE_USER");
  const pwd = parseStringEnv("DATABASE_PWD");
  const dbname = parseStringEnv("DATABASE_NAME");

  return `mongodb://${user}:${pwd}@${host}:${port}/${dbname}?authSource=admin&ssl=false`;
};

export const env = {
  JWT_SECRET: parseStringEnv("JWT_SECRET"),
  PORT_BACKEND: parseIntEnv("PORT_BACKEND"),
  CLIENT_HOST: parseStringEnv("CLIENT_HOST"),
  ENABLE_CORS: parseBoolEnv("ENABLE_CORS"),
  MONGO_URI: parseMongoString(),
};

export type Env = typeof env;

我想用它来设置应用程序运行的端口以及 Mongoose 的连接参数:

在main.ts中:

<rest of the code>
await app.listen(env.PORT_BACKEND || 8080);
<rest of the code>

现在,神奇的事情从这里开始 - 当仅导入 ConfigModule 时,应用程序可以正常启动。它也将在没有 ConfigModule 和添加 require('doting').config() 的情况下开始。当我添加 MongooseModule 时,应用程序崩溃,因为它无法解析 env - 最棒的是抛出的异常与用于创建 MONGO_URI 的 env 无关!!我从解析器中得到“Invalid env JWT_SECRET”。

在app.module.ts

import { Module } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
import { MongooseModule } from "@nestjs/mongoose";

import { AppController } from "./app.controller";
import { env } from "./common/env";

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),
    MongooseModule.forRoot(env.MONGO_URI), //WTF?
  ],
  controllers: [AppController],
})
export class AppModule {}

老实说,我只是 运行 不知道哪里出了问题。解析器在我的上一个项目中工作得很好(但我没有使用 Mongoose,所以这可能是导致问题的原因)。下面是我的 .env 文件模板。

JWT_SECRET=
ENABLE_CORS=
PORT_BACKEND=
DATABASE_HOST=
DATABASE_PORT=
DATABASE_USER=
DATABASE_PWD
DATABASE_NAME=
CLIENT_HOST=

感谢所有花时间帮助我的人 ;)

您正在导入 env.ts 之前 ConfigModule 已导入并在您的 .env 文件中设置变量。

这就是调用 require('dotenv').config() 有效的原因。在幕后,这就是 ConfigModule 为您所做的。但是,您对 ConfigModule.forRoot 的调用发生在 在您导入 env.ts 之后 ,因此尚未导入 .env 文件并且那些变量没有尚不存在。

我强烈建议您查看 custom configuration files,它以“嵌套方式”为您处理此问题:

来自 Nest 文档,但请注意,您也可以使用已有的 env.ts 文件:

// env.ts
export default () => ({
  // Add your own properties here however you'd like
  port: parseInt(process.env.PORT, 10) || 3000,
  database: {
    host: process.env.DATABASE_HOST,
    port: parseInt(process.env.DATABASE_PORT, 10) || 5432
  }
});

然后将您的 AppModule 修改为以下内容。请注意,我们正在使用 forRootAsync 以便我们可以获得 ConfigService 的句柄并从中获取变量。

// app.module.ts
import configuration from './common/env';

@Module({
  imports: [
    ConfigModule.forRoot({
      load: [configuration],
    }),
    //  
    MongooseModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        uri: configService.get<string>('MONGO_URI'),
      }),
      inject: [ConfigService],
    });
  ],
})
export class AppModule {}

作为替代方案,您也可以在顶部的 env.ts 文件中调用 require('dotenv').config(),但您会错过所有 ConfigModule 助手,例如 dev/prod .env 个文件。

在我的例子中,我将@types/node 降级为与我的节点版本相同的版本。可能是一个提示。

在我的例子中只需要更换订单导入模块。

import { Module } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
import { MongooseModule } from "@nestjs/mongoose";

import { AppController } from "./app.controller";
import { env } from "./common/env"; // call process.env.xxx here > undefined

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }), // process.env.xxx must be called after this line
    MongooseModule.forRoot(env.MONGO_URI),
  ],
  controllers: [AppController],
})
export class AppModule {}

所以修复

import { Module } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
// should place this at very first line
const envModule = ConfigModule.forRoot({
   isGlobal: true,
})

import { MongooseModule } from "@nestjs/mongoose";

import { AppController } from "./app.controller";
import { env } from "./common/env";

@Module({
  imports: [
    envModule,
    MongooseModule.forRoot(env.MONGO_URI),
  ],
  controllers: [AppController],
})
export class AppModule {}

通过使用 JWT 模块的 registerAsync 并读取 process.env 内部的 useFactory 方法对我有用

@Module({
  imports: [
    JwtModule.registerAsync({
      useFactory: () => ({
        secret: process.env.JWT_SECRET_KEY,
        signOptions: { expiresIn: 3600 },
      }),
    })
  ],
  controllers: [AppController],
})