首页 > 解决方案 > 为什么我无法在节点 js 中更新 env 变量

问题描述

我想在节点 js 中更新我的 env 变量,但我无法更新它的 env 变量,我尝试过console.log(process.env.DB_HOST)但我仍然得到旧值,在这里我添加了我的整个代码,任何人都可以查看它,并且帮我解决这个问题,

function exec_api() { 
    return new Promise(async function (resolve) {
        const execSync = require('child_process').exec;
        //let child_process_obj = execSync('DB_HOST='+process.env.UNITTEST_DB_HOST+' DB_DATABASE='+process.env.UNITTEST_DB_DATABASE+'  DB_USERNAME='+process.env.UNITTEST_DB_USERNAME+' DB_PASSWORD='+process.env.UNITTEST_DB_PASSWORD+'  PORT='+process.env.UNITTEST_SERVICE_PORT+' ./node_modules/.bin/nodemon main.js'); 
        await execSync('export DB_HOST=' + process.env.UNITTEST_DB_HOST);
        await execSync('export DB_DATABASE=' + process.env.UNITTEST_DB_DATABASE);
        await execSync('export DB_USERNAME=' + process.env.UNITTEST_DB_USERNAME);
        await execSync('export DB_PASSWORD=' + process.env.UNITTEST_DB_PASSWORD);
        await execSync('export PORT=' + process.env.UNITTEST_API_BACKEND_PORT);
        let child_process_obj = await execSync('node main.js');
        unittest_api_backend_process_id = child_process_obj.pid;
        resolve(true);
    });
}

标签: node.jsnode-modules

解决方案


TLDR:只需更改 process.env

要更改、添加或删除环境变量,请使用process.env. 以下是显示其工作原理的测试代码:

main.js 中

console.log(process.env.DB_DATABASE);

exec.js 中

const execSync = require ('child_process').execSync;

process.env.DB_DATABASE = 'foo'; // this is ALL you need to do

console.log(execSync('node main.js').toString('utf8'));

使用上面的两个文件,如果您运行,node exec.js您将在控制台中看到foo打印出来的内容。main.js这是从继承环境的打印出来的exec.js

因此,您需要在代码中做的就是:

我想在节点 js 中更新我的 env 变量,但我无法更新它的 env 变量,我尝试使用 console.log(process.env.DB_HOST) 但我仍然得到旧值,在这里我添加了我的整个代码, 有没有人可以看看, 并帮助我解决这个问题,

function exec_api() { 
    return new Promise(function (resolve) {
        const exec = require('child_process').exec;

        // The following is node.js equivalent of bash "export":
        process.env.DB_HOST = process.env.UNITTEST_DB_HOST;
        process.env.DB_DATABASE = process.env.UNITTEST_DB_DATABASE;
        process.env.DB_USERNAME = process.env.UNITTEST_DB_USERNAME;
        process.env.DB_PASSWORD = process.env.UNITTEST_DB_PASSWORD;
        process.env.PORT = process.env.UNITTEST_SERVICE_PORT;

        let child_process_obj = exec('node main.js', {
            stdio: ['inherit', 'inherit', 'inherit']
        });

        unittest_api_backend_process_id = child_process_obj.pid;

        resolve(true);
    });
}

请注意,如果您希望承诺在main.js结束时返回,您需要执行以下操作:

function exec_api() { 
    return new Promise(function (resolve) {
        const exec = require('child_process').exec;

        // The following is node.js equivalent of bash "export":
        process.env.DB_HOST = process.env.UNITTEST_DB_HOST;
        process.env.DB_DATABASE = process.env.UNITTEST_DB_DATABASE;
        process.env.DB_USERNAME = process.env.UNITTEST_DB_USERNAME;
        process.env.DB_PASSWORD = process.env.UNITTEST_DB_PASSWORD;
        process.env.PORT = process.env.UNITTEST_SERVICE_PORT;

        let child_process_obj = exec('node main.js', {
            stdio: ['inherit', 'inherit', 'inherit']
        });

        unittest_api_backend_process_id = child_process_obj.pid;

        child_process_obj.on('exit', () => resolve(true));

        // ^^^ Cannot use `await` as the API is not promise based
        //     but event based instead.
    });
}

长话短说:为什么export不起作用的完整解释

在 unixen 上,环境变量,甚至整个环境,包括当前工作目录、根目录(可以通过 chroot 更改)等,都不是 shell 的特性。它们是过程的特征。

我们可能熟悉export一些 shell 为子进程设置环境变量的语法,但这就是 shell 的语法。它与环境变量本身无关。例如,C/C++ 不使用export,而是使用setenv()函数设置环境变量(实际上,在内部这就是 bash/sh/ksh 等在实现时所做的export)。

在 node.js 中,读取和设置环境变量的机制是通过process.env.

为什么要求外壳做它不起作用

这不仅仅是一个 node.js 问题。它也不会在 bash 中工作:

exporter.sh中:

#! /bin/bash

export DB_DATABASE=$1

exec.sh 中

#! /bin/bash

./exporter.sh foo
echo $DB_DATABASE ;# does not print "foo"

这是 unixen 的一个核心安全特性:不应该允许其他用户弄乱你的进程。在环境的情况下执行此策略的方式是只有父进程才能设置子进程的环境。不允许子进程设置父进程的环境。假设是子进程属于父进程,所以你应该被允许对程序做你想做的事情 - 但是由于父进程(你)不属于子进程,所以不允许子进程搞乱父母的环境。

这就是为什么您尝试使用export不起作用的原因。它确实有效(变量确实是在子shell中创建的)但不允许改变它的父环境(node.js进程)


推荐阅读