dotenv 完全指南:在 Ruby 与 Rails 中优雅加载 .env 环境变量 【免费下载链接】dotenvA Ruby gem to load environment variables from .env.项目地址https://gitcode.com/gh_mirrors/dot/dotenv点击查看免费下载dotenv 是 Ruby 生态中最流行的环境变量加载工具它把配置存于环境这一 十二因子应用twelve-factor app 的理念落地为一行代码在开发环境启动时将项目根目录.env文件中的键值对加载进ENV。本文将围绕本仓库版本 3.2.0的 README.md 展开从安装、Ruby/Rails/Sinatra/Rake 集成、CLI 命令、.env语法解析到测试自动恢复、必填键校验、模板生成与常见问答并结合 lib/dotenv.rb、lib/dotenv/parser.rb、lib/dotenv/cli.rb 等源码与 spec/dotenv/parser_spec.rb、spec/dotenv_spec.rb 等测试用例帮助你从会用进阶到懂原理。为什么需要 dotenv配置与代码分离在部署环境中数据库连接串、外部服务凭据等随环境变化的配置应当从代码中抽离到环境变量里而不是硬编码进源码。十二因子应用将其列为一条铁律。但在开发机或 CI 服务器上往往同时运行着多个项目为每个项目手工设置环境变量并不现实。dotenv 解决的就是这个痛点它会在应用启动bootstrap时从.env文件把变量加载进ENV让开发环境也能像生产环境一样通过环境变量读取配置。从源码结构看整个 gem 的核心链路非常清晰Dotenv.parse 将每个文件包装为 Dotenv::Environment 并解析Dotenv.load 通过update将解析结果写入ENVDotenv::Parser 负责.env文本到键值对的语法转换。安装在应用 Gemfile 顶部添加如下一行然后执行bundle installgem dotenv, groups: [:development, :test]从 dotenv.gemspec 可以看到dotenv 要求 Ruby 版本 3.0若要在 Rails 中使用还需要安装dotenv-railsgem见 dotenv-rails.gemspec其依赖railties 6.1即dotenv 3.x 仅支持 Rails 6.1 及以上版本更低版本请使用 dotenv ~ 2.0这一点在 lib/dotenv/rails.rb 的启动检查中会给出警告。基本用法创建.env并读取在项目根目录创建.env文件写入应用配置S3_BUCKETYOURS3BUCKET SECRET_KEYYOURSECRETKEYGOESHERE每当应用加载时这些变量就会出现在ENV中可直接按常规方式使用config.fog_directory ENV[S3_BUCKET]加载多个文件与加载语义默认情况下load会在当前工作目录查找名为.env的文件也可以传入多个文件它们会按传入顺序依次加载见 lib/dotenv.rb 的parse实现多个文件通过reduce逐个合并require dotenv Dotenv.load(file1.env, file2.env)加载时有三条关键语义均有源码与测试佐证先到先得对于同一个变量第一个被设置的值胜出first value wins。对应 spec/dotenv/parser_spec.rb 中的redefined variable 返回已存在值测试不覆盖已有变量已存在的环境变量不会被覆盖除非设置overwrite: true。在 lib/dotenv.rb 的update方法中ENV.update的冲突分支根据overwrite取值决定保留旧值false还是新值true忽略缺失文件文件不存在时默认静默跳过ignore: true仅当捕获到Errno::ENOENT/Errno::EISDIR且ignore为 false 时才抛出异常lib/dotenv.rb。若希望缺失文件直接报错可使用Dotenv.load!。相关的四个核心方法lib/dotenv.rb 提供了基于load的一组变体方法便于按需选择方法行为Dotenv.load(*files)默认行为不覆盖已有变量忽略缺失文件Dotenv.load!(*files)同load但缺失文件时抛出Errno::ENOENTDotenv.overwrite(*files)别名overload同load但覆盖已有ENV值Dotenv.overwrite!(*files)别名overload!同overwrite且缺失文件时抛错注意overwrite模式下的加载顺序源码中filenames filenames.reverse if overwritelib/dotenv.rb文件列表会被反转从而保证排在前面的文件优先级更高——这一点在 spec/dotenv_spec.rb 的 overwrite 测试中有明确验证。Rails 集成在 Rails 应用中dotenv 会在应用启动时自动加载无需任何额外代码。加载发生在before_configuration回调中见 lib/dotenv/rails.rb即config/application.rb中class Application Rails::Application定义 Application 常量触发之时。如果希望更早加载或自定义加载流程可以在application.rb顶部手动干预。dotenv-rails 还默认将 ActiveSupport::Notifications 挂接为 instrumenter并通过 Dotenv::LogSubscriber 输出 Loaded ... / Set ... / Restored ... 等日志同时如果应用使用了 Spring加载过的.env文件会被自动加入 Spring 的 watch 列表lib/dotenv/rails.rb改动后无需重启。Sinatra / Ruby尽早加载对于 Sinatra 或纯 Ruby 应用需要在引导bootstrap过程中尽可能早地加载 dotenvrequire dotenv/load # 或 require dotenv Dotenv.loadrequire dotenv/load是推荐方式它等价于加载 dotenv 并立即调用Dotenv.loadlib/dotenv/load.rb 中仅两行require dotenv后根据是否定义了Dotenv::Rails调用Dotenv::Rails.load或Dotenv.load。这也是加载顺序一节中让依赖环境变量的 gem 提前拿到变量的关键。测试中的自动恢复Autorestore自 3.0 起Rails 应用中的 dotenv 会在每个测试结束后自动恢复ENV因此你可以在测试中随意修改ENV而不用担心状态泄漏到其他用例。它同时支持ActiveSupport::TestCase与 RSpec。实现细节见 lib/dotenv/autorestore.rbRSpec 下通过before(:suite) { Dotenv.save }与after { Dotenv.restore }挂钩ActiveSupport 下则在setup/teardown中调用同样的 save/restore。配套的 test/autorestore_test.rb 中两个连续用例互相断言对方修改的ENV[DOTENV]已被清除直观展示了隔离效果。如需关闭该行为在config/application.rb或config/environments/test.rb中设置config.dotenv.autorestore false如果应用使用了 climate_control 的初始化判断对应 spec/dotenv/rails_spec.rb 的测试。在非 Rails 应用中使用此能力只需在测试套件中require dotenv/autorestore手动控制 ENV 的保存与恢复lib/dotenv.rb 还提供了三个底层 API供手动场景使用Dotenv.save快照当前ENV内部通过 Dotenv::Diff 记录初始状态snapshot会生成一份冻结的ENV.to_h.dupDotenv.restore恢复到最近一次保存的状态。注意它不是线程安全的——在非主线程调用会抛出ThreadErrorlib/dotenv.rb对应测试见 spec/dotenv_spec.rbDotenv.modify(hash) { ... }在块执行期间临时修改ENV块结束后自动恢复。该方法通过内部SEMAPHORE一个Monitor同步多个线程对ENV的修改会被串行化lib/dotenv.rb因此是线程安全的修改方式。Rake 任务集成为了让.env在 Rake 任务执行前被加载引入 dotenv 的任务并声明依赖require dotenv/tasks task mytask: :dotenv do # things that require .env endlib/dotenv/tasks.rb 定义了:dotenv任务内部require dotenv后执行Dotenv.load并额外让environment任务依赖:dotenv——这意味着在 Rails 场景下任何依赖environment的 Rake 任务都会先加载.env。命令行 CLIdotenv 提供了dotenv可执行文件可以在启动应用前先把.env加载进环境$ dotenv ./script.rb-f指定配置文件列表-f的值是逗号分隔的配置文件列表按重要性从高到低排列。注意-f与值之间必须有一个空格且所有列出的文件都必须存在否则命令会失败见 spec/dotenv/cli_spec.rb 的 dies if file specified by -f doesnt exist 测试$ dotenv -f .env.local,.env ./script.rb-i/--ignore忽略缺失文件配合-f使用-i或--ignore可以容忍列表中部分文件不存在。例如下面的命令中若.env.local不存在则忽略它、只加载.env$ dotenv -i -f .env.local,.env ./script.rb对应 CLI 实现中on(-i, --ignore, ...)设置ignore true最终以Dotenv.load(*filenames, overwrite: overwrite, ignore: ignore)执行lib/dotenv/cli.rb。-o/--overwrite覆盖已有变量默认情况下 CLI 与 Ruby API 一致不会覆盖已存在的环境变量。若需要覆盖使用-o或--overwrite$ dotenv -o -f .env.local,.env--overload是该 flag 的另一个别名lib/dotenv/cli.rb。其他 flagCLI 还支持-h/--help查看帮助、-v/--version输出版本号以及-t/--templateFILE生成模板详见下文模板一节。需要留意的是dotenv只会消费自己的 flag不会误吞传给子命令的参数——spec/dotenv/cli_spec.rb 验证了dotenv -f plain.env foo --switch中foo --switch会原样保留给子命令。加载顺序Load Order如果你使用的某个 gem 要求在它被加载之前环境变量就已就绪那么在Gemfile中把 dotenv 排在该 gem 之前并显式require dotenv/loadgem dotenv, require: dotenv/load gem gem-that-requires-env-variables这样 Bundler 会按 Gemfile 顺序加载dotenv 先行完成ENV填充。旧版的require dotenv/rails-now已废弃lib/dotenv/rails-now.rb 会给出弃用警告并转向dotenv/load。自定义 Rails 加载环境文件优先级在 Rails 应用中dotenv 会依据RAILS_ENV加载下列文件第一个文件优先级最高.env优先级最低优先级developmenttestproduction是否 .gitignore说明最高.env.development.local.env.test.local.env.production.local是环境专属本地覆盖第 2.env.localN/A.env.local是本地覆盖第 3.env.development.env.test.env.production否环境共享变量最后.env.env.env视情况所有环境共享这一文件列表的生成逻辑见 lib/dotenv/rails.rb默认数组为[.env.#{env}.local, (.env.local unless env.test?), .env.#{env}, .env]并compact因此test 环境不会加载.env.local对应 spec/dotenv/rails_spec.rb 的测试。此外dotenv 对 Rake 任务做了特殊处理当RAILS_ENV未显式指定而运行default、test、spec等任务时会按 test 环境推断lib/dotenv/rails.rb。这些文件在before_configuration回调期间被加载。如果需要更早初始化或想自定义加载过程可以在config/application.rb顶部操作# config/application.rb Bundler.require(*Rails.groups) # Load .env.local in test Dotenv::Rails.files.unshift(.env.local) if ENV[RAILS_ENV] test module YourApp class Application Rails::Application # ... end end可用的配置选项Dotenv::Rails.files要加载的文件列表按优先级排列可通过追加见 spec/dotenv/rails_spec.rbDotenv::Rails.overwrite是否用.env*文件内容覆盖已有ENV变量默认falseDotenv::Rails.loggerdotenv 日志使用的 logger默认Rails.logger在 Rails 日志器尚未就绪时使用 Dotenv::ReplayLogger 暂存日志、就绪后再回放见 lib/dotenv/rails.rbDotenv::Rails.autorestore启用或禁用测试中的 autorestore。.env文件语法详解以下语法规则均有 lib/dotenv/parser.rb 的正则实现与 spec/dotenv/parser_spec.rb 的测试支撑。多行值Multi-line values含换行的多行值必须用双引号包围PRIVATE_KEY-----BEGIN RSA PRIVATE KEY----- ... HkVN9... ... -----END DSA PRIVATE KEY-----3.0 之前的旧行为是在带引号字符串中把\n替换为真实换行该行为现已弃用。若要恢复旧行为在包含\n的变量之前设置DOTENV_LINEBREAK_MODElegacyDOTENV_LINEBREAK_MODElegacy PRIVATE_KEY-----BEGIN RSA PRIVATE KEY-----\nHkVN9...\n-----END DSA PRIVATE KEY-----\n从实现看Parser#expand_newlines会检查当前文件内或ENV中的DOTENV_LINEBREAK_MODE是否等于legacylib/dotenv/parser.rblegacy 模式将\n/\r展开为真实换行严格模式则保留为字面\n/\r对应 spec/dotenv/parser_spec.rb 的测试。另外Environment#read 以rb:bom|utf-8模式读取文件因此带 UTF-8 BOM 的文件也能正确解析spec/dotenv_spec.rb 对此有专门测试。命令替换Command Substitution想把某条命令的输出放进变量用$(your_command)即可DATABASE_URLpostgres://$(whoami)localhost/my_database实现位于 lib/dotenv/substitutions/command.rb它用支持嵌套平衡括号的正则匹配$(...)然后通过反引号执行命令并chomp掉尾部换行若命令前有反斜杠转义\$(...)则不执行、保留字面量。测试覆盖了嵌套括号、命令内引号、命令→变量→命令链等场景spec/dotenv/parser_spec.rb。注意该替换仅在RUBY_VERSION 1.8.7时启用lib/dotenv/parser.rb且 JRuby / Rubinius 上不支持在命令中再展开 shell 变量。变量替换Variable Substitution想引用另一个变量的值在无引号或双引号的值中用${VAR}或直接$VARDATABASE_URLpostgres://${USER}localhost/my_databaselib/dotenv/substitutions/variable.rb 的实现要点展开顺序是先查当前解析文件内已定义的变量再查外部ENV都找不到则展开为空字符串env[match[3]] || ENV[match[3]] || 如果值里的$不是想作为变量引用请用单引号包裹——单引号内的值不做任何替换与转义PASSWORDpas$word反斜杠转义的变量\$VAR、\${VAR}不会被展开保留字面$VAR测试见 spec/dotenv/parser_spec.rb。注释Comments支持整行注释与行尾注释# This is a comment SECRET_KEYYOURSECRETKEYGOESHERE # comment SECRET_HASHsomething-with-a-#-hash解析器正则的(?:\#.*)?部分负责剥离行尾注释但带引号值内部的#会原样保留SECRET_HASH的值为something-with-a-#-hash。导出Exports出于兼容性考虑可以在每行前面加export这样文件也能直接在 bash 中sourceexport S3_BUCKETYOURS3BUCKET export SECRET_KEYYOURSECRETKEYGOESHERE解析时export前缀会被剥离仅提取键值。值得注意的是解析器还支持YAML 风格的KEY: value分隔写法见 spec/fixtures/yaml.env 与 spec/dotenv/parser_spec.rb。另外键名允许包含点号如FOO.BARfoobar正则中(?key[\w.])即为此设计。键名中允许出现哪些字符从 lib/dotenv/parser.rb 的LINE正则可以归纳.env语法键由\w字母、数字、下划线和点号组成分隔符支持可带空格或:YAML 风格值可以是单引号、双引号或无引号字符串每行支持行首行尾空白与可选注释。单引号字符串内允许\转义双引号内允许\转义未加引号的值不能包含#与换行。必填键校验Required Keys如果某个配置值必须存在而当前未设置dotenv 允许在初始化阶段直接抛错从而把配置缺失问题提前暴露——这比在生产运行时才报错要安全得多。推荐在config/initializers/dotenv.rb中声明# config/initializers/dotenv.rb Dotenv.require_keys(SERVICE_APP_ID, SERVICE_KEY, SERVICE_SECRET)只要上述任一键未设置应用初始化就会抛出 Dotenv::MissingKeys 异常错误信息形如Missing required configuration keys: [TEST1, TEST2]。实现上require_keys用keys.flatten - ::ENV.keys计算缺失集合lib/dotenv.rbspec/dotenv_spec.rb 分别验证了缺失单个与多个键的报错文案。程序化解析Parsing如果只想检查env 文件内容而不修改ENV可以使用Dotenv.parseDotenv.parse(.env.local, .env) # {S3_BUCKET YOURS3BUCKET, SECRET_KEY YOURSECRETKEYGOESHERE, ...}该方法返回变量名/值组成的 Hash且不会写入ENVspec/dotenv_spec.rb 明确验证了这一点。它同样默认回退到.env文件并支持 tilde 路径展开。模板生成Templates团队协作时通常希望提交一份不含真实密钥的模板文件。dotenv CLI 的-t或--template可以从.env生成模板$ dotenv -t .env模板会生成在工作目录命名为{原文件名}.template——上面的命令会创建.env.template。模板保留所有变量名但值被替换为变量名本身# .env S3_BUCKETYOURS3BUCKET SECRET_KEYYOURSECRETKEYGOESHERE会变成# .env.template S3_BUCKETS3_BUCKET SECRET_KEYSECRET_KEY实现位于 lib/dotenv/template.rb 的EnvTemplate#create_template逐行处理注释行与空行原样保留export前缀也会保留export FOOFOO多行引号值同样能正确折叠成单行变量名测试见 spec/dotenv/cli_spec.rb。常见问题FAQ生产环境可以用 dotenv 吗dotenv 最初是为开发环境把配置加载进ENV而生的。生产环境通常有更合适的管理方式例如由 Puppet 或 Chef 管理的/etc/environment、heroku config等。不过也有人觉得 dotenv 在 staging/production 下配置 Rails 很方便——只要定义.env.production、.env.test这类环境专属文件即可。如果你用本 gem 管理多个 Rails 环境的变量请遵循这条约定所有环境通用的变量放.env环境专属的变量放.env.环境名。应该把.env提交进版本库吗凭据只应存在于需要访问它的机器上绝不要把并非每台开发机/服务器都需要的敏感信息提交进仓库。作者本人的偏好是提交只含开发环境设置的.env这样新成员克隆后能立刻上手、又不会泄露其他环境的凭据。若采纳此建议请务必保证开发环境的凭据与其他部署环境完全不同且开发凭据无权访问任何机密数据。为什么没有覆盖已有的ENV变量默认情况下 dotenv不会覆盖已有环境变量——这是刻意设计部署环境通常比应用本身更了解正确的配置。如需覆盖Dotenv.load files, overwrite: true如果想在某个值未被覆盖时给出警告例如为了让使用者意识到这个坑使用Dotenv.load files, overwrite: :warnoverwrite: :warn会在冲突时输出Warning: dotenv not overwriting ENV[KEY]并保留旧值lib/dotenv.rb注意不会打印值本身以防泄露密钥测试见 spec/dotenv_spec.rb。CLI 下则用-o/--overwriteflag$ dotenv -o -f .env.local,.env总结dotenv 的哲学可以用一句话概括把环境变量当作一等配置载体用.env文件弥合开发环境与部署环境之间的差距。从安装、多文件加载语义先到先得、默认不覆盖、可忽略缺失文件到 Rails 的环境文件优先级表、测试自动恢复、Rake/CLI 集成再到多行值、命令替换、变量替换、注释、导出等解析规则配合必填键校验、程序化解析与模板生成这套工具链覆盖了日常开发中几乎全部的环境变量管理场景。源码层面的 parser.rb、dotenv.rb 与 rails.rb 各司其职测试用例parser_spec.rb、dotenv_spec.rb、rails_spec.rb则为上述每一种行为提供了可验证的保证值得在接入自己的项目时逐一对照实践。赞分享【免费下载链接】dotenvA Ruby gem to load environment variables from .env.项目地址https://gitcode.com/gh_mirrors/dot/dotenv点击查看免费下载相关推荐TIL在 npm scripts 中加载并使用 .env 环境变量dotenv-cli cross-varTIL在 npm scripts 中加载并使用 .env 环境变量dotenv cli cross var 本篇技术指南来自本项目til即 To文档教程知识库dotenv 完全指南用零依赖模块在 Node.js 中加载 .env 环境变量含 CLI 与源码级解析dotenv 完全指南用零依赖模块在 Node.js 中加载 .env 环境变量含 CLI 与源码级解析 dotenv 是一个零依赖的 Node.js 模开发工具后端PHP dotenv 完全指南从 .env 文件加载环境变量、嵌套插值与配置校验PHP dotenv 完全指南从 .env 文件加载环境变量、嵌套插值与配置校验 phpdotenv Composer 包名 vlucas/phpdoten后端开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考