revel.config按固定顺序加载配置:先读conf/app.conf(必须存在),再用conf/production.conf或conf/dev.conf(依revel_runmode而定)覆盖同名key,最后由环境变量(如revel_db_host)兜底覆盖,且运行中修改文件不会自动重载。

revel.Config 读取 app.conf 的实际行为
Revel 的 revel.Config 不是简单加载某个文件,而是按固定顺序查找并合并多个配置源:先读 conf/app.conf(必须存在),再尝试覆盖同名 key 的 conf/production.conf 或 conf/dev.conf(取决于 REVEL_RUNMODE),最后用环境变量兜底。这意味着写死在 app.conf 里的值可能被运行时环境变量悄悄覆盖,调试时容易误判。
常见误区:
-
revel.Config.String("db.host")返回空,不一定是配置没写,可能是REVEL_RUNMODE=prod但conf/production.conf里漏写了该字段,此时会 fallback 到空字符串而非报错 - 配置项名区分大小写,
db.port和DB.Port是两个键;注释用#,不是// - 路径中含空格或特殊字符(如
data_dir = ./db files/)必须用双引号包裹,否则解析失败
环境变量如何覆盖 revel.Config 的 key
Revel 默认支持通过环境变量覆盖配置项,规则是:将配置 key 全大写、点号转下划线、加前缀 REVEL_。例如 db.host 对应 REVEL_DB_HOST,app.name 对应 REVEL_APP_NAME。这个机制在 Docker 或 systemd 部署时非常实用,但容易踩坑:
- 如果环境变量值为空字符串(
export REVEL_DB_PORT=""),它会覆盖掉app.conf中的非空默认值,导致连接失败 -
REVEL_RUNMODE本身也是环境变量,它决定加载哪个conf/*.conf文件——但它不会被自己覆盖,所以必须在启动前设置好 - Windows 下设置环境变量需用
set REVEL_DB_HOST=127.0.0.1,而不是export,且 cmd.exe 不支持变量继承到子进程,建议用 PowerShell 或批处理封装启动
自定义配置段和类型转换的陷阱
Revel 支持用 [section] 分组配置,例如 [db] 或 [redis],但调用时必须显式指定 section 名,不能省略。比如 revel.Config.String("host") 读不到 [db] host = 127.0.0.1,必须写成 revel.Config.String("db.host")。
类型转换函数(Int()、Bool()、Duration())在失败时不 panic,而是返回零值 + error。生产代码中必须检查 error:
port, err := revel.Config.Int("http.port")
if err != nil {
revel.ERROR.Fatal("invalid http.port in config: %v", err)
}
-
Bool()只认true/false字符串,不识别1/0或on/off -
Duration()使用 Go 的time.ParseDuration规则,"30s"合法,"30 seconds"非法 - 数组或 map 类型不被原生支持,需自行解析字符串(如用
strings.Split处理逗号分隔的 hosts 列表)
为什么 revel.Config 有时读不到刚改的配置
Revel 在应用启动时一次性加载并缓存全部配置,运行中修改 conf/app.conf 文件不会自动重载。开发阶段看似“热更新”,其实是 revel run 检测到文件变化后重启了整个进程,而非框架内 reload。
- 在
revel build生成的二进制中,配置是静态打包进去的,改磁盘上的conf/目录完全无效——必须重新 build - Docker 容器内挂载配置文件时,若用
bind mount替换整个conf/目录,需确保新文件权限为容器内用户可读(常见错误:root 写的文件,revel 进程以 non-root 用户运行) - 测试时用
revel.TestSuite,它默认不加载conf/,需手动调用revel.Init()并传入测试目录路径,否则revel.Config为 nil
db.password 很可能被一个空的 REVEL_DB_PASSWORD 静默清空。











