相关文章推荐
痛苦的领带  ·  MySQL用GROUP ...·  1 年前    · 
飞奔的柚子  ·  python ...·  1 年前    · 
失恋的牙膏  ·  spring - The bean ...·  1 年前    · 
定制Node.js的.env文件

应用程序通常需要部署到许多不同的环境,包括暂存、测试和生产,而不需要构建特定环境的工件。

像12因素应用程序这样的方法论规定,应用程序的代码和配置是分开的,但在部署期间结合起来以适应特定的环境。

环境变量是定义和消费特定环境配置值的首选方法之一,因为它们受到所有主要操作系统的支持。

它们可以在大多数云提供商的平台即服务(PaaS)产品中定义,并且是配置平台(如Docker)的一种常见方法。

然而,有时在本地配置文件中定义应用程序的设置也很方便。

例如,在本地开发和调试应用程序时,特别是在跨许多功能分支工作时,在文件中定义一组环境变量的能力简化了开发人员的经验。

.env 文件为定义环境变量提供了一个流行的解决方案,特别是在Node.js中。例如,像Heroku这样的平台,使用 .env 文件作为他们推荐的最佳实践的一部分。

在这篇文章中,我们将看看一个通过环境变量配置的简单Node.js应用程序,并探讨如何用覆盖默认值的新环境变量定制一个 .env 文件。

然后我们将演示如何使用多个定制的 .env 文件来快速切换多个特定环境配置。

我们将使用的示例应用程序在GitHub上提供 。要在本地运行该应用程序,请 确保已安装Node.js

另外,你也可以 在CodeSandBox中运行该应用程序 。点击链接,在一个新的沙盒中打开GitHub
源代码,以构建、运行并通过一个随机的URL进行展示。

Node.js应用程序的样本

下面的代码显示了一个简单的Node.js网络服务器,配置了两个环境变量: PORT ,它定义了网络服务器监听的端口,以及 MYNAME ,它定义了HTTP响应中返回的名称。

const http = require('http');
const port = parseInt(process.env.PORT, 10) || 5000;
const name = process.env.MYNAME || "Matthew"
http.createServer((request, response) => {
    response.writeHead(200, {
        'Content-Type': 'text/plain'
    response.write('Hello, ' + name + '!');
    response.end();
}).listen(port);

首先导入http 模块。

const http = require('http');

我们可以尝试从PORT 环境变量中解析出一个整数值,如果环境变量没有定义或包含整数以外的内容,则默认为端口5000。

const port = parseInt(process.env.PORT, 10) || 5000;

HTTP响应中返回的名称可以在MYNAME 环境变量中找到,或者默认为字符串Matthew

const name = process.env.MYNAME || "Matthew"

在Web服务器启动后,它将监听我们刚才定义的端口。

http.createServer((request, response) => {
  // ...
}).listen(port);

HTTP响应是在传递给createServer() 的函数中构建的。在这里,我们返回上面定义的名称。

    response.writeHead(200, {
        'Content-Type': 'text/plain'
    response.write('Hello, ' + name + '!');
    response.end();

现在,我们可以用以下方式运行应用程序。

node index.js

打开http://localhost:5000,看到Hello, Matthew! 响应,这意味着我们的Node.js应用程序正在正常运行。

为什么我们需要覆盖环境变量?

为什么首先要费尽心思用环境变量来覆盖数值,比如端口号?

这些值已经可以作为命令行参数传入,或者从JSON或YAML配置文件中加载,比环境变量暴露出简单的名称和值对提供了更多的灵活性。

然而,由于PaaS解决方案经常需要从环境变量中读取数值,PORT 环境变量成为定义应用程序监听的端口的事实标准。

例如,HerokuAWSAzureGoogle Cloud都要求部署在其服务上的Node.js应用程序监听由PORT 环境变量定义的端口。

在十二因素应用方法论等方法论中,也经常要求使用明确定义的环境变量。

在帖子的介绍中,我们注意到这种方法论需要在代码之外定义应用程序的配置;Twelve-Factor App配置部分有更详细的介绍。

十二因素应用程序将配置存储在环境变量(通常简称为env vars或env)中。环境变量很容易在部署之间改变,而不需要改变任何代码;与配置文件不同,它们很少有机会被意外地检查到代码库中;而且与自定义配置文件或其他配置机制(如Java系统属性)不同,它们是一种语言和操作系统无关的标准。-"十二个因素的应用程序",亚当-威金

通过环境变量配置我们的应用程序,我们可以确保我们的代码易于在各种平台上进行部署和定制。

在Node.js中设置环境变量

部署到PaaS解决方案的Node.js应用程序通常必须假定该应用程序正在监听一个随机数字的端口。我们可以通过将PORT 环境变量设置为5000以外的值来在本地演示这一点。

我们还将设置MYNAME 环境变量来演示如何定义应用程序的特定配置。

在Linux和macOS中,我们可以像这样定义这些环境变量。

PORT=5001 MYNAME=Jane node src/index.js

在Windows PowerShell中,我们可以像下面这样定义环境变量。

$env:PORT="5001"
$env:MYNAME="Jane"
node src\index.js

对于我们的两个环境变量来说,这个过程是可控的,但如果我们必须在应用程序每次运行时定义几十个环境变量,那么这个过程很快就会变得很乏味。在.env 文件中定义环境变量提供了一个方便的解决方案。

在Node.js中加载.env 文件

Node.js没有原生加载.env 文件,所以我们必须使用dotenv 包来加载文件,并通过process.env公开数值

首先,在package.json 文件中的dependencies 属性下,将dotenv 作为项目的依赖关系。

"name": "node-env-file-demo", "version": "1.0.0", "description": "Node.js example loading .env files", "main": "src/index.js", "scripts": { "start": "nodemon src/index.js" "dependencies": { "dotenv": "10.0.0" "devDependencies": { "nodemon": "1.18.4" "keywords": []

接下来,用以下方式下载该依赖关系。

npm install

为了加载.env 文件,我们必须加载dotenv 包并在index.js 文件的开头调用configure() 函数。

require('dotenv').config();
const http = require('http');
const port = parseInt(process.env.PORT, 10) || 5000;
const name = process.env.MYNAME || "Matthew"
http.createServer((request, response) => {
    response.writeHead(200, {
        'Content-Type': 'text/plain'
    response.write('Hello, ' + name + '!');
    response.end();
}).listen(port);

我们的应用程序现在已经准备好加载.env 文件。

在Node.js中定义自定义环境变量

我们现在可以在项目的根目录下创建.env 文件。

定制一个.env 文件包括在每一行的开头定义我们想要覆盖的环境变量名称,然后是= 和变量的值。在下面的例子中,我们为PORTMYNAME 环境变量定义了新值。

PORT=5001
MYNAME=Jane

现在,用下面的命令运行该应用程序。

node src/index.js

接下来,打开http://localhost:5001;注意到端口的变化和返回的信息Hello, Jane!

预加载dotenv

在我们的代码中调用require('dotenv').config() 的另一种方法是使用-r--require 命令行选项来预加载dotenv

node -r dotenv/config src/index.js

这种方法将环境变量注入到Node.js应用程序中,否则不支持.env 文件,而无需编辑原始源代码。

在Node.js中使用多个.env 文件

为了让开发人员在开发过程中快速交换许多自定义的环境文件,我们可以配置dotenv ,通过DOTENV_CONFIG_PATH 环境变量从自定义文件加载环境变量。

为了证明这一点,在项目的根目录下创建一个名为.env.development 的文件,内容如下。

PORT=5002
MYNAME=Jill

然后,将DOTENV_CONFIG_PATH 环境变量设置为.env.development ,并使用我们刚才介绍的预加载方法运行该应用程序。

在Windows PowerShell上,用这些命令运行该应用程序。

$env:DOTENV_CONFIG_PATH=".env.development"
node -r dotenv/config src/index.js

在Linux或macOS上,用这个命令运行该应用程序。

DOTENV_CONFIG_PATH=.env.development node -r dotenv/config src/index.js

我们的应用程序现在可以在http://localhost:5002,并会返回Hello, Jill!

.env 文件排除在 Git 之外

因为.env 文件通常包含敏感信息,比如数据库连接字符串,我们不想把这些值提交到 Git 仓库。如果我们这样做,我们就会与任何可以访问应用程序源代码的人分享我们的密码。

环境变量很好地避免了这个问题,因为就其本质而言,环境变量的值并不在文件中定义。然而,我们必须将.env 文件从 Git 仓库中排除,以防止共享它们。

要做到这一点,我们可以在项目的根目录下创建一个名为.gitignore 的文件,并添加以下一行。

.env*

现在,Git 忽略了.env 文件和其他任何以.env 开头的文件,如.env.development ,这意味着任何敏感信息都不会出现在我们的 Git 仓库里。