简体   繁体   English

何时在 NodeJS 应用程序中加载 .env 变量?

[英]When to load .env variables in NodeJS app?

I am coding a simple NodeJS Express REST API, using TypeScript.我正在使用 TypeScript 编写一个简单的 NodeJS Express REST API。 I have some environment variables that I load with dotenv .我有一些使用dotenv加载的环境变量。

I access my .env variables at two different stages in my code: index.ts , which is my start file, and in a MyControllerClass.ts file.我在代码中的两个不同阶段访问我的.env变量: index.ts ,这是我的起始文件,以及MyControllerClass.ts文件。 To access these variables, the code is process.env.MY_ENV_VAR .要访问这些变量,代码是process.env.MY_ENV_VAR To load them for the application, the code is dotenv.config() .要为应用程序加载它们,代码是dotenv.config()

As my index.ts file seems to be the root of my program (I configure my app in it), I use dotenv.config() to load my .env file for the rest of the program.由于我的index.ts文件似乎是我的程序的根目录(我在其中配置了我的应用程序),因此我使用dotenv.config()为程序的其余部分加载我的.env文件。 However, in my MyControllerClass.ts file, in the constructor, if I do console.log(process.env.MY_ENV_VAR) , I get " undefined ".但是,在我的MyControllerClass.ts文件中,在构造函数中,如果我执行console.log(process.env.MY_ENV_VAR) ,我会得到“ undefined ”。 I could workaround this by adding a dotenv.config() in my constructor (it works) but it's nonsense to me to have it here.我可以通过在我的构造函数中添加一个dotenv.config()来解决这个问题(它有效),但在这里拥有它对我来说是无稽之谈。

How do I use dotenv.config() once and for all in my program, in a readable manner (like in an appropriate .ts file)?如何以可读的方式(例如在适当的 .ts 文件中)在我的程序中一劳永逸地使用dotenv.config() ) ? and more generally: what is a NodeJS Express loading cycle?更一般地说:什么是 NodeJS Express 加载周期?

Here is a sample of the file structure of my code这是我的代码的文件结构示例

src
├── index.ts
├── Authentication
│   └── authentication.router.ts
│   └── authentication.controller.ts

Here is the code of index.js这是 index.js 的代码

/**
 * Required External Modules
 */
 import * as dotenv from "dotenv";
 import express from "express";
 import cors from "cors";
 import helmet from "helmet";
 import { authenticationRouter } from "./authentication/authentication.router"

 dotenv.config();

 /**
 * App Variables
 */
 if(!process.env.PORT) {
    process.exit(1);
}
const PORT: number = parseInt(process.env.PORT as string, 10);
const app = express();

/**
 *  App Configuration
 */
 app.use(helmet());
 app.use(cors());
 app.use(express.json());
 app.use(authenticationRouter);

 app.use("api/authenticate/", authenticationRouter);
/**
 * Server Activation
 */
 app.listen(PORT, () => {
    console.log(`Listening on port ${PORT}`);
  });

Here is the code of authentication.router.ts这是authentication.router.ts的代码

import express, { Request, Response } from "express";
import { AuthenticatorController } from "./authentication.controller";
export const authenticationRouter = express.Router();
const authenticatorController = AuthenticatorController.getInstance();

authenticationRouter.post("/api/authenticate", async (req: Request, res: Response) => {   
    try {
        if (await authenticatorController.authenticate(req.body.login, req.body.password)) {
            res.send({"status": "ok"})
        } else
            res.send({"status": "Error"})
    } catch (e) {
        console.debug(e)
        res.send({"status": "500"});
    }
    
});

Here is the code of authentication.controller.ts这是authentication.controller.ts的代码

import { ClientSecretCredential } from "@azure/identity";
import { SecretClient } from "@azure/keyvault-secrets";
import { Authenticator } from "./api/Authenticator";
import * as dotenv from "dotenv";
dotenv.config();

export class AuthenticatorController implements Authenticator {
    
    private static singleInstance: AuthenticatorController | null = null;
    private azureSecretCredential= new ClientSecretCredential(
        process.env.AZURE_TENANT_ID as string,
        process.env.AZURE_CLIENT_ID as string,
        process.env.AZURE_CLIENT_SECRET as string);
    private azureSecretClient = new SecretClient(
        process.env.KEY_VAULT_URL as string,
        this.azureSecretCredential);

    private constructor () {}

    public static getInstance(): AuthenticatorController {
        if (this.singleInstance === null) {
            this.singleInstance = new AuthenticatorController();
        }
        return this.singleInstance;
    }

    public async authenticate(login: string, password: string): Promise<Boolean> {
        let isAuthenticated = false;

        try {
            const secret = await this.azureSecretClient.getSecret(login)
            if (secret.name === login) {
                if (secret.value === password) {
                    isAuthenticated = true;
                }
            }
        }   catch (e) {
            console.debug(e);
        }
            return isAuthenticated;
    }
}

You only call dotenv.config() once:你只调用dotenv.config()一次:

As early as possible in your application, require and configure dotenv.尽早在您的应用程序中,要求并配置 dotenv。

require('dotenv').config()

Therefore index.ts seems to be correct, process.env should then hold your parsed values.因此 index.ts 似乎是正确的,然后process.env应该保存您解析的值。 Maybe you can use something like this to make sure, data is parsed correctly:也许您可以使用这样的方法来确保正确解析数据:

const result = dotenv.config();

if (result.error) {
  throw result.error;
}

console.log(result.parsed);

Edit:编辑:

You can try the following.您可以尝试以下操作。 I changed your exports a bit, because there is no need for a singleton within your controller.我稍微更改了您的导出,因为您的控制器中不需要单例。

authentication.router.ts: authentication.router.ts:

// Imports (no dotenv; no dotenv.config())
// [...]

// Import controller
import { authenticatorController } from "./authentication.controller";

export const authenticationRouter = express.Router();

// Adding routes
// [...]

authentication.controller.ts: authentication.controller.ts:

// Imports (no dotenv; no dotenv.config())
// [...]

class AuthenticatorController implements Authenticator {
  // [...]
}

export const authenticatorController = new AuthenticatorController();

index.ts:索引.ts:

// Imports (dotenv)
// [...]

const { error, parsed } = dotenv.config();

if (error) {
  throw error;
}

console.log(parsed);

// [...]

 app.use("api/authenticate/", authenticationRouter);

// [...]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM