此文译自: # Introducing Env: a better way to read environment variables in JavaScript
在 JavaScript 中读取环境变量充满风险。Env 让它变得更好。
如果您编写服务器端 JavaScript,您可能需要从环境变量中读取信息。在环境变量中共享敏感信息(如访问令牌)以确保它们的安全被认为是最佳实践。然而,从 JavaScript 读取环境变量的方式很容易出错,可能需要花费数小时才能弄明白。当读取环境变量时发生错误时,您希望立即知道,并且不想解释隐藏的错误消息。这就是Env的用武之地。
安装环境
Env 1是一个零依赖实用程序,旨在使读取环境变量更安全且不易出错。它通过解决服务器端 JavaScript 中与环境变量相关错误的根本原因来实现这一点。它适用于 Node.js 和 Deno,并根据正在使用的运行时从正确的位置自动读取环境变量。
要在 Node.js 中使用 Env,请使用 npm 安装它:
$ npm install @humanwhocodes/env
然后导入Env构造函数:
import { Env } from "@humanwhocodes/env";
// or
const { Env } = require("@humanwhocodes/env");
要在 Deno 中使用 Env,请从 Skypack 中引用它:
import { Env } from "https://cdn.skypack.dev/@humanwhocodes/env?dts";
一旦你有了Env构造函数,你就可以像这样创建一个新实例:
const env = new Env();
现在您已准备好安全地读取环境变量。
问题 1:缺少环境变量
Env 解决的第一个问题是如何处理丢失的环境变量。环境变量丢失是很常见的,要么是因为它们不小心没有正确设置,要么是因为它们只存在于某些容器而不是全部容器中。在任何情况下,您都希望无缝处理丢失的环境变量。在 Node.js 中,您可能会执行以下操作:
const USERNAME = process.env.USERNAME || "guest";
此处的目的是使用USERNAME环境变量(如果存在),如果不存在,则默认为"guest"。Env 对此进行了简化,以明确设置默认值:
const USERNAME = env.get("USERNAME", "guest");
此代码具有相同的效果,但避免了过程中的任何类型强制。当然,这是假设 USERNAME 失踪是可以的。但是,如果您绝对需要一个环境变量才能让您的应用程序正常工作,该怎么办?为此,您可以编写如下代码:
const USERNAME = process.env.USERNAME;
if (!USERNAME) {
throw new Error("Environment variable USERNAME is missing.");
}
这是用于一些简单验证的大量代码,如果您有多个必需的环境变量,您最终会为每个环境变量重复此模式。使用 Env,您可以使用以下require()方法:
const USERNAME = env.require("USERNAME");
如果USERNAME此示例中缺少环境变量,则会抛出错误告诉您。您还可以required以类似的方式使用该属性:
const USERNAME = env.required.USERNAME;
此语法允许您避免键入字符串,但如果USERNAME不存在,仍会抛出错误。
问题 2:错别字
环境变量常见的另一类错误是拼写错误。当您多次输入同一内容时,很难发现错别字。例如,您可以输入如下内容:
const USERNAME = process.env.USERRNAME;
就我个人而言,我花了几个小时来追踪我在代码中错误输入环境变量与名称相关的错误。无论出于何种原因,我都正确输入了变量名,但没有输入环境变量名。如果您希望您的 JavaScript 变量与某些必需的环境变量具有相同的名称,您可以使用required属性的解构来只输入一次名称:
const {
PORT,
HOST
} = env.required;
这里,两个局部变量PORT和HOST是从同名的环境变量中创建的。如果缺少任一环境变量,则会引发错误。
问题 3:类型不匹配
环境变量的另一种微妙错误是类型不匹配。例如,考虑以下 Node.js 代码:
const PORT = process.env.PORT || 8080;
这条线或类似的东西出现在很多 Node.js 应用程序中。大多数时候它不会引起问题……但它可能会引起问题。你能发现问题吗?
所有环境变量都是字符串,因此PORT当环境变量存在时,JavaScript 变量是一个字符串,如果不存在则是一个数字。在 Deno 中使用类似的代码会引发错误2,我花了一段时间才弄明白。事实证明,Deno HTTP 服务器要求端口是一个数字,所以它在本地运行良好,但是当我将它部署到 Cloud Run 时,我收到了一个错误。
为了解决这个问题,Env 自动将所有默认值转换为字符串:
const PORT = env.get("PORT", 8080);
console.log(typeof PORT === "string"); // always true
即使您传入一个非字符串值作为默认值,Env 也会将其转换为字符串以确保您在读取环境变量时只收到字符串值。
问题 4:回退变量
有时您可能想要检查多个环境变量,并且仅在没有任何环境变量存在时才使用默认值。所以你的代码可能是这样的:
const PORT = process.env.PORT || process.env.HTTP_PORT || 8080;
您可以使用 Env 使其更加清晰:
const PORT = env.first(["PORT", "HTTP_PORT"], 8080);
使用此代码,Env 从它找到的第一个环境变量中返回一个值。与 类似get(),first()允许您传入默认值以在未找到任何环境变量时使用,并且该默认值会自动转换为字符串。作为附加的错误检查,如果第一个参数不是数组或者是只有一个项目的数组,则会抛出错误。
结论
Env 是对我来说非常有价值的实用程序之一,我有时会忘记提及它。在过去的两年里,我一直在许多个人项目中使用它,它为我节省了很多时间。调试与环境变量相关的错误并不是任何人的乐趣,我无法计算我被环境错误拯救的次数。我希望你也觉得它有帮助。