环境变量
欢迎来到“Javascript:技巧与窍门”系列博客。在本系列博客中,我将向您展示一些开发技巧,并解决我在软件工程师职业生涯中遇到的一些问题。
每次编写后端应用程序时,无论采用何种技术栈,我们都需要对应用程序进行一些配置,例如令牌、端点、密钥等等。有很多原因需要避免“硬编码”(将这些值保存在代码库中)。例如,出于安全考虑(我们不想暴露凭据信息)、动态变量(端点、端口等)、可扩展性(多服务器和多环境)等等。
市面上有很多工具(付费的和免费的)可供你使用。但是等等!我们真的总是需要一个单独的应用程序来处理配置吗?答案是否定的。
环境变量
环境变量是由操作系统托管的键值存储。可以把它想象成一个 JavaScript 变量,只不过它是在程序外部定义的。大多数现代操作系统都支持环境变量。环境变量与进程绑定。这意味着你可以为某个进程定义一个名为 PORT 的变量,并将其值设为 80,也可以为另一个进程定义一个名为 PORT 的变量,并将其值设为 8080。它们之间不会相互冲突。
使用 Node.js 时,运行时环境变量会通过“process.env”加载并可供访问。我们来看一个例子:创建一个名为 app.js 的文件。
const http = require('http');
http.createServer().listen(8080).on('listening', ()=>{
console.log('listening on port ' + 8080);
});
运行 app.js
node app.js
您会在控制台中看到正在监听 8080 端口。现在,让我们使用环境变量。
const http = require('http');
http.createServer().listen(process.env.PORT).on('listening', ()=>{
console.log('listening on port ' + process.env.PORT);
});
现在你需要运行:
PORT=8080 node app.js
这里你在 app.js 的作用域内定义了一个名为 PORT 的变量,并将其赋值为 8080。需要注意的是,变量 port 只能在 app.js 运行的进程中访问。
现在让我们更有创意一些。
const http = require('http');
const port = (process.env.NODE_ENV === 'prod') ? process.env.PROD_PORT : process.env.DEV_PORT
http.createServer().listen(port).on('listening', ()=>{
console.log('listening on port ' + port);
});
现在我们需要定义三个变量:NODE_ENV、PROD_PORT、DEV_PORT。
如果想以开发模式运行应用程序,应该运行:
PROD_PORT=3000 NODE_ENV=dev DEV_PORT=8080 node app.js
结果:正在监听端口 8080
生产模式:
PROD_PORT=3000 NODE_ENV=prod DEV_PORT=8080 node app.js
结果:正在监听端口 3000
我想你已经意识到这种方法的弊端了。首先,当变量数量增加时,管理起来会很困难,而且容易出错。
多滕夫
dotenv 是一个库,它可以将所有环境变量从 .env 文件加载到 process.env 文件中。这是一种非常便捷的方式,可以将配置与代码库分离。现在让我们重写应用程序。首先,安装 dotenv:
npm install dotenv
现在我们有了 dotenv,请在根目录下创建一个名为 .env 的文件:
NODE_ENV=prod
PROD_PORT=3000
DEV_PORT=8080
我们需要使用 dotenv 加载环境变量:
require('dotenv').config();
const http = require('http');
const port = (process.env.NODE_ENV === 'prod') ? process.env.PROD_PORT : process.env.DEV_PORT
http.createServer().listen(port).on('listening', ()=>{
console.log('listening on port ' + port);
});
现在只需运行 app.js 即可!是不是很简单?但是请记住,如果您在 .env 文件中保存了任何机密信息,例如密码、密钥、令牌等……千万不要将 .env 文件放在代码库中。请将其单独保存在安全的地方。同时,请确保将 .env 文件包含在您的 .gitignore 文件中。
我现在担心的是,如果我们的部署出了问题,由于某种原因,我们在运行时忘记包含 .env 文件怎么办?解决这个问题的方法有很多,最简单的方法就是使用 if 语句。但我今天想谈谈我最喜欢的方法。
乔伊
Joi 是一款功能强大的验证工具。它允许您创建复杂的模式并实时验证对象。让我们来创建自己的模式:首先,安装 Joi。
npm install @hapi/joi
Joi 的声明式语法非常简单。
const joi = require('@hapi/joi');
const envSchema = joi.object({
devPort: joi.number().required(),
prodPort: joi.number().required(),
env: joi.string().required(),
});
现在验证就这么简单:
const http = require('http');
const joi = require('@hapi/joi');
require('dotenv').config();
const envSchema = joi.object({
devPort: joi.number().required(),
prodPort: joi.number().required(),
env: joi.string().required(),
});
const environment = envSchema.validate({
devPort: process.env.DEV_PORT,
prodPort: process.env.PROD_PORT,
env: process.env.NODE_ENV,
});
if (environment.error)
throw (environment.error);
const port = (environment.value.env === 'prod') ? environment.value.prodPort : environment.value.devPort;
http.createServer().listen(port).on('listening', ()=>{
console.log('listening on port ' + port);
});
当你声明一个 Joi schema 时,它会公开一个名为 validate 的方法,该方法接受一个值并将其与你声明的 schema 进行比较。它会返回一个包含值和错误信息的对象。如果在验证过程中没有发生错误,则错误信息应为 null,你可以使用该值继续执行你的代码。但如果错误信息不为 null,则表示验证失败。接下来,你可以自行决定如何处理这个错误。就我而言,我希望抛出错误并终止进程。
您可以尝试在 .env 文件中包含或排除一些必需的值,并查看上述代码片段的不同结果。现在,为了分离关注点,让我们将环境与 app.js 分离。首先,创建一个名为 environment.js 的文件:
const joi = require('@hapi/joi');
require('dotenv').config();
const envSchema = joi.object({
devPort: joi.number().required(),
prodPort: joi.number().required(),
env: joi.string().required(),
});
module.exports = envSchema.validate({
devPort: process.env.DEV_PORT,
prodPort: process.env.PROD_PORT,
env: process.env.NODE_ENV,
});
现在我们的 app.js 文件应该如下所示:
const http = require('http');
const environment = require('./environment');
if (environment.error)
throw (environment.error);
const port = (environment.value.env === 'prod') ? environment.value.prodPort : environment.value.devPort;
http.createServer().listen(port).on('listening', ()=>{
console.log('listening on port ' + port);
});
很简单,对吧?现在您可以放心了。如果您的部署出现问题,您的部署团队会发现并修复它。
结论
今天我们学习了环境变量以及如何利用它们来提高应用程序的安全性和可扩展性。我们讨论了 dotenv,并探讨了使用该库如何降低代码库出错的概率。此外,我们还介绍了 Joi,以及如何创建模式和验证对象。
希望您喜欢我今天的博客,下次我将讨论“如何根据异步函数过滤数组!”
文章来源:https://dev.to/pharzad/environment-variables-332l