提示:多个单词组合在一起可以构成了一个复合名词(compound noun)
前言
提示:如果出现这个错误看一下这两句话就可以了,不用往下看了[doge]
问题:使用viper读取YAML配置文件的时候,当一个字段由多个单词组成的时候(比如YAML配置文件里面jwt的secret_key字段),读取不到值
解决方法:viper推荐使用mapstructure标签进行映射
,即项目中配置结构体的字段使用mapstructure标签进行映射
提示:以下是本篇文章正文内容,下面案例可供参考
一、从出现问题到找到问题根源
下面是一个极其简陋的YAML配置文件,位于项目根目录下
(标注:秘钥是拿来测试用的,等会再随机生成一个,所以是不存在泄露问题的[doge])
settings.yaml
mysql:
host: 127.0.0.1
port: 3306
user: root
password: 123456
dbname: gvb_db
redis:
host: 127.0.0.1
port: 6379
password:
system:
host: 0.0.0.0
port: 8190
env: dev
log:
level: info
filename: logs/app.log
max_size: 100
max_backups: 5
max_age: 7
compress: true
jwt:
secret_key: b08f2e537d494dee0f044e6c69ec7b24c6e68f6c5e4e2783a0774277bc343515 # 替换为你的密钥
expiration: 24h # 令牌过期时间,这里是24小时
core/config.go
func LoadConfig() (*config.Config, error) {
viper.SetConfigName("settings") // name of config file (without extension)
viper.AddConfigPath(".") // optionally look for config in the working directory
err := viper.ReadInConfig() // Find and read the config file
if err != nil {
return nil, fmt.Errorf("failed to read config: %w", err)
}
// 下面四行代码仅限于测试使用,第一行是打印文件路径,第二行是打印所有键值,第三四行是测试能否读到jwt的配置
fmt.Println("Config loaded:", viper.ConfigFileUsed())
fmt.Println("Config loaded:", viper.AllKeys())
fmt.Println("Config loaded:", viper.GetString("jwt.expiration"))
fmt.Println("Config loaded:", viper.GetString("jwt.secret_key"))
var cfg config.Config
err = viper.Unmarshal(&cfg)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
}
return &cfg, nil
}
出现问题的时候(即使用viper读取YAML配置文件的时候,当一个字段由多个单词组成的时候(比如YAML配置文件里面jwt的secret_key字段),读取不到)
我使用fmt.Println("Config loaded:", viper.AllKeys())
发现viper.ReadInConfig() 已经读取了所有的配置键了,如下图,数组里面的即为键
同时以下代码均打印了键对应的值
fmt.Println("Config loaded:", viper.GetString("jwt.expiration"))
fmt.Println("Config loaded:", viper.GetString("jwt.secret_key"))
如下图
所以问题出现在了viper将配置映射到项目的config结构体的时候出错了
即err = viper.Unmarshal(&cfg)
这一句代码出错啦
二、以下是问题处理的全过程
以下是问题处理的全过程:
问题:使用viper读取配置文件的时候,当一个字段由多个单词组成的时候(比如YAML配置文件里面jwt的secret_key字段),读取不到值,
原因:代码err = viper.Unmarshal(&cfg)
出现问题,即,将配置文件映射到配置结构体中,复合名词字段映射失败,无法得到值
- 查看版本号,go list -m github.com/spf13/viper
- 更新版本 go get -u github.com/spf13/viper,发现还是读取不到值。通过更新解决bug的方法失败,此路不通
- 更换配置文件,将YAML配置文件更换为TOML配置文件
- golang应用中对该JWT配置的引用都与我的settings.yaml文件保持一致的,即结构体字段使用将标签yaml改为标签toml
- 发现还是读取不到值。通过更换配置文件的方法失败,此路不通
- 更改复合名词的格式
- 将
_
间隔更改为-
,即secret_key更改为secret-key,结构体标签yaml里面的值也跟着同步。结果失败,没有读取到值 - 同理,更改为小驼峰和大驼峰命名法,结构体标签yaml里面的值也跟着同步。结果失败,没有读取到值。更改复合名词的格式的方法失败。
- 将
- 后面发现viper推荐使用mapstructure标签进行映射
- golang应用中对该JWT配置的引用,即结构体字段使用将标签mapstructure即可
- 成功读取到值!使用mapstructure标签进行映射的方法成功,撒花!
现在解决了,通过项目中配置结构体里面字段的标签添加上mapstructure标签即可
下面是有问题的代码
type JWTConfig struct {
Secret string `yaml:"secretKey"` // 密钥
Expiration string `yaml:"expiration"` // 过期时间
}
将上面代码添加上mapstructure标签即可,当然,项目配置结构体的标签一般要一致,所以我所有的配置结构体字段都添加上了,已经在改了,在改了,还好不多哈哈
type JWTConfig struct {
Secret string `yaml:"secret_key" mapstructure:"secret_key"` // 密钥
Expiration string `yaml:"expiration"` // 过期时间
}
总结
viper推荐使用mapstructure标签进行映射
,即项目中配置结构体的字段使用mapstructure标签进行映射,其他标签也能映射,但容易出现问题。