环境变量

环境变量

环境变量用于在应用程序代码库之外存储机密信息,如数据库密码、应用程序密钥或 API 密钥。

此外,环境变量还可以用于为不同环境提供不同的配置。例如,你可能在测试期间使用内存邮件发送器,在开发期间使用 SMTP 邮件发送器,而在生产环境中使用第三方服务。

由于所有操作系统、部署平台和 CI/CD 管道都支持环境变量,它们已成为存储机密信息和特定于环境的配置的实际标准。

在本指南中,我们将学习如何在 AdonisJS 应用程序中利用环境变量。

读取环境变量

Node.js 通过 process.env 全局属性 原生地将所有环境变量作为一个对象暴露出来,你可以通过以下方式访问它们:

process.env.NODE_ENV
process.env.HOST
process.env.PORT

使用 AdonisJS 的 env 模块

虽然通过 process.env 对象读取环境变量在 Node.js 运行时中无需 AdonisJS 方面的任何设置,但在本文档的其余部分,我们将使用 AdonisJS 的 env 模块,原因如下:

  • 能够从多个 .env 文件中存储和解析环境变量。
  • 在应用程序启动时立即验证环境变量。
  • 为经过验证的环境变量提供静态类型安全性。

env 模块在 start/env.ts 文件中实例化,你可以在应用程序中的其他地方按如下方式访问它。

import env from '#start/env'
env.get('NODE_ENV')
env.get('HOST')
env.get('PORT')
// Returns 3333 when PORT is undefined
env.get('PORT', 3333)

在 Edge 模板中共享 env 模块

如果你想在Edge模板中访问环境变量,那么你必须将 env 模块作为全局变量与 Edge 模板共享。

你可以在 start 目录中 创建一个 view.ts 作为预加载文件,并在其中编写以下代码行。

start/view.ts
import env from '#start/env'
import edge from 'edge.js'
edge.global('env', env)

验证环境变量

环境变量的验证规则是在 start/env.ts 文件中使用 Env.create 方法定义的。

当你首次导入此文件时,验证会自动执行。通常,start/env.ts 文件是由你项目中的某个配置文件导入的。如果不是,那么 AdonisJS 会在启动应用程序之前隐式地导入此文件。

Env.create 方法接受一个键值对作为验证模式。

  • 键是环境变量的名称。
  • 值是执行验证的函数。它可以是自定义的内联函数,或者是对预定义模式方法(如 schema.stringschema.number )的引用。
import Env from '@adonisjs/core/env'
/**
* App root is used to locate .env files inside
* the project root.
*/
const APP_ROOT = new URL('../', import.meta.url)
export default await Env.create(APP_ROOT, {
HOST: Env.schema.string({ format: 'host' }),
PORT: Env.schema.number(),
APP_KEY: Env.schema.string(),
APP_NAME: Env.schema.string(),
CACHE_VIEWS: Env.schema.boolean(),
SESSION_DRIVER: Env.schema.string(),
NODE_ENV: Env.schema.enum([
'development',
'production',
'test'
] as const),
})

静态类型信息

相同的验证规则也用于推断静态类型信息。在使用 env 模块时,可以获取类型信息。

验证器模式 API

schema.string

schema.string 方法确保值是有效的字符串。空字符串无法通过验证,如果允许空字符串,则必须使用可选变体。

{
APP_KEY: Env.schema.string()
}
// Mark APP_KEY to be optional
{
APP_KEY: Env.schema.string.optional()
}

可以对字符串值的格式进行验证。以下是可用的格式列表。

host

验证该值是否为有效的 URL 或 IP 地址。

{
HOST: Env.schema.string({ format: 'host' })
}

url

验证该值是否为有效的 URL。可选地,你可以通过允许没有 protocoltld 的 URL 来放宽验证的严格性。

{
S3_ENDPOINT: Env.schema.string({ format: 'url' })
// 允许URL没有协议
S3_ENDPOINT: Env.schema.string({ format: 'url', protocol: false })
// 允许URL没有域名后缀
S3_ENDPOINT: Env.schema.string({ format: 'url', tld: false })
}

email

验证该值是否为有效的电子邮件地址。

{
SENDER_EMAIL: Env.schema.string({ format: 'email' })
}

schema.boolean

schema.boolean 方法确保值是有效的布尔类型。空值无法通过验证,如果允许空值,则必须使用可选变体。

字符串表示形式 'true''1''false''0' 会被转换为布尔数据类型。

{
CACHE_VIEWS: Env.schema.boolean()
}
// Mark it as optional
{
CACHE_VIEWS: Env.schema.boolean.optional()
}

schema.number

schema.number 方法确保值是有效的数字。数字值的字符串表示形式会被转换为数字数据类型。

{
PORT: Env.schema.number()
}
// Mark it as optional
{
PORT: Env.schema.number.optional()
}

schema.enum

schema.enum 方法用于验证环境变量是否为预定义值之一。枚举选项可以指定为值的数组或 TypeScript 原生枚举类型。

{
NODE_ENV: Env
.schema
.enum(['development', 'production'] as const)
}
// Mark it as optional
{
NODE_ENV: Env
.schema
.enum
.optional(['development', 'production'] as const)
}
// Using native enums
enum NODE_ENV {
development = 'development',
production = 'production'
}
{
NODE_ENV: Env.schema.enum(NODE_ENV)
}

自定义函数

自定义函数可以执行模式 API 未涵盖的验证。

该函数接收环境变量的名称作为第一个参数,接收值作为第二个参数。它必须返回验证后的最终值。

{
PORT: (name, value) => {
if (!value) {
throw new Error('Value for PORT is required')
}
if (isNaN(Number(value))) {
throw new Error('Value for PORT must be a valid number')
}
return Number(value)
}
}

定义环境变量

在开发环境中

在开发期间,环境变量是在 .env 文件中定义的。env 模块会在项目的根目录中查找此文件,并自动解析它(如果存在)。

.env
PORT=3333
HOST=0.0.0.0
NODE_ENV=development
APP_KEY=sH2k88gojcp3PdAJiGDxof54kjtTXa3g
SESSION_DRIVER=cookie
CACHE_VIEWS=false

在生产环境中

建议在生产环境中使用你的部署平台来定义环境变量。大多数现代的部署平台都支持通过其 Web UI 来定义环境变量。

如果你的部署平台不提供定义环境变量的方式。你可以在项目根目录或生产服务器上的其他位置创建一个 .env 文件。

AdonisJS 会自动从项目根目录读取 .env 文件。但是,如果.env 文件存储在其他位置,则必须设置 ENV_PATH 变量。

# Attempts to read .env file from project root
node server.js
# Reads the .env file from the "/etc/secrets" directory
ENV_PATH=/etc/secrets node server.js

在测试期间

测试环境特有的环境变量必须在 .env.test 文件中定义。此文件中的值将覆盖 .env 文件中的值。

.env
NODE_ENV=development
SESSION_DRIVER=cookie
ASSETS_DRIVER=vite
.env.test
NODE_ENV=test
SESSION_DRIVER=memory
ASSETS_DRIVER=fake
// During tests
import env from '#start/env'
env.get('SESSION_DRIVER') // memory

所有其他 dot-env 文件

除了 .env 文件外,AdonisJS 还会处理以下点环境文件中的环境变量。因此,你可以根据需要选择性地创建这些文件。

排名最靠前的文件会覆盖排名较低的文件中的值。

排名 文件名 备注
1st .env.[NODE_ENV].local 根据当前的 NODE_ENV 加载。例如,如果 NODE_ENV 设置为 development ,则会加载 .env.development.local文件。
2nd .env.local 在除 testtesting 环境之外的所有环境中加载
3rd .env.[NODE_ENV] 根据当前的 NODE_ENV 加载。例如,如果 NODE_ENV 设置为 development,则会加载 .env.development 文件。
4th .env 在所有环境中加载。如果在此文件中存储机密信息,应将其添加到 .gitignore 中。

在 dot-env 文件中使用变量

在 dot-env 文件中,你可以使用变量替换语法引用其他环境变量。

在以下示例中,我们根据 HOST 和 PORT 属性计算 APP_URL。

HOST=localhost
PORT=3333
URL=$HOST:$PORT

所有位于$符号之后的 字母数字 以及 下划线 (_) 都用于构成变量名。如果变量名包含除下划线以外的特殊字符,则必须使用花括号 {} 将变量名括起来。

REDIS-USER=admin
REDIS-URL=localhost@${REDIS-USER}

转义 $ 符号

若要将 $ 符号用作值,必须对其进行转义,以防止发生变量替换。

PASSWORD=pa\$\$word