gin多环境配置需通过env变量控制viper动态加载config.{env}.yaml,禁用init()初始化,生产优先用环境变量或json,强制校验必填字段并匹配gin.setmode。

你需要让同一个Gin应用在开发、测试、生产环境里加载不同配置,比如开发连本地MySQL、测试连预发库、生产连云数据库,同时避免配置泄露和启动失败。
用ENV变量控制配置加载路径
第一步:在项目根目录创建三个配置文件——config.dev.yaml、config.test.yaml、config.prod.yaml,内容结构一致但字段值不同,例如数据库地址、日志级别、服务端口。
第二步:在main.go开头读取环境变量,【必须在viper初始化前调用os.Getenv("ENV")】,否则viper会默认加载config.yaml而忽略后缀;若未设置ENV,则默认为dev。
第三步:用viper.SetConfigName("config." + env)动态指定文件名,再调用viper.AddConfigPath(".")添加当前目录为搜索路径,最后执行viper.ReadInConfig()加载。
这一步操作起来很简单,直接把文件拖进去就行,但别在init()函数里做——单元测试时无法mock环境变量,会导致测试失败。
生产环境禁用YAML,优先走环境变量
方法一:生产部署时,不挂载config.prod.yaml文件,而是通过Docker或K8s注入APP_DB_HOST=10.0.1.5、APP_HTTP_PORT=8080等变量,代码中启用viper.AutomaticEnv()并设viper.SetEnvPrefix("APP")。
方法二:如果必须用文件,生产上改用config.prod.json,调viper.SetConfigType("json"),因为JSON解析快、无类型隐式转换(YAML会把yes/no自动转布尔值,线上出问题难排查)。
注意:所有配置项必须有默认值,否则viper.GetString("db.host")返回空字符串却不报错,服务启动成功但后续请求直接panic。
校验配置是否真正可用
步骤一:viper.ReadInConfig()成功只代表文件存在且语法合法,不代表字段都填了。在main()函数里手动检查关键字段,比如if viper.GetString("database.host") == "" { log.Fatal("missing database.host") }。
步骤二:对敏感字段如redis.addr、jwt.secret做非空校验,失败立即os.Exit(1),比让服务起来后第一个请求才崩更早暴露问题。
步骤三:测试环境启动时,额外验证配置与当前ENV是否匹配——比如ENV=test但viper.GetString("server.mode") != "test",说明配置文件写错了。
这一步不能跳过,否则CI/CD流水线里本地用dev跑通了,上线却连错数据库。
设置Gin运行模式匹配环境
根据ENV变量值,调用gin.SetMode()切换框架内置行为:ENV=dev → gin.SetMode(gin.DebugMode),ENV=prod → gin.SetMode(gin.ReleaseMode),ENV=test → gin.SetMode(gin.TestMode)。
生产环境必须设为ReleaseMode,否则HTTP响应体里会暴露panic堆栈,严重泄露路径和变量名。
gin.Default()默认启用Logger和Recovery中间件,适合开发;生产环境应改用gin.New(),自己按需加中间件,比如只加Recovery(),日志改用zap结构化输出。











