【问题标题】:Using viper to read config from envfile使用 viper 从 envfile 读取配置
【发布时间】:2020-08-21 17:43:14
【问题描述】:

我真的不明白 viper 的工作原理。 这是我的代码:

configuration.go

var Config *Configuration

type ServerConfiguration struct {
    Port string
}

type Configuration struct {
    Server   ServerConfiguration
}

func Init() {
    var configuration *Configuration
    viper.SetConfigFile(".env")
    viper.AutomaticEnv()
    if err := viper.ReadInConfig(); err != nil {
        log.Fatalf("Error reading config file, %s", err)
    }

    err := viper.Unmarshal(&configuration)
    if err != nil {
        log.Fatalf("Unable to decode into struct, %v", err)
    }

    Config = configuration
}

func GetConfig() *Configuration {
    return Config
}

.env SERVER_PORT=:4747

问题是 Unmarshal 不起作用 例如,当我使用 configuration.Server.Port 时,它是空的

【问题讨论】:

  • 我会发表评论,但我的声誉还不够高。您的代码在我的机器上运行。我建议在您的值上测试 viper.Get(FullName) 以查看是否可以获得它们。至于在 .env 中使用 _ 嵌套变量,请使用新的 viper 实例:v := viper.NewWithOptions(viper.KeyDelimiter("_"))

标签: go viper-go


【解决方案1】:

spf13/viper 主要使用 mapstructure 包将一种原生 Go 类型转换为另一种,即在解组时。该包在内部使用map[string]interface{} 类型来存储您的配置(请参阅viper.go - L1327)。之后,根据配置类型(您的情况是env),viper 调用正确的解析包来存储您的配置值。对于 envfile 类型,它使用subosito/gotenv 放入上述映射类型(参见viper.go - L1501

您的问题的症结在于如何让 viper 在映射中将此配置解组为您选择的结构。这是 mapstructure 包进来的地方,将地图解组为您定义的嵌套结构。此时,您有两个选择

  1. 将配置解组为 map[string]interface{} 类型,然后使用 mapstructure 放入适当的结构
  2. 使用DecodeHookFunc 作为方法的第二个参数来解组配置(请参阅viper.go - L904

为了简单起见,您可以做一个,根据我用您的示例复制的一个简单示例,可以在下面完成

package main

import (
    "fmt"
    "github.com/mitchellh/mapstructure"
    "github.com/spf13/viper"
)

type ServerConfiguration struct {
    Port string `mapstructure:"server_port"`
}

type Configuration struct {
    Server ServerConfiguration `mapstructure:",squash"`
}

func main() {
    var result map[string]interface{}
    var config Configuration
    viper.SetConfigFile(".env")
    if err := viper.ReadInConfig(); err != nil {
        fmt.Printf("Error reading config file, %s", err)
    }

    err := viper.Unmarshal(&result)
    if err != nil {
        fmt.Printf("Unable to decode into map, %v", err)
    }

    decErr := mapstructure.Decode(result, &config)

    if decErr != nil {
        fmt.Println("error decoding")
    }

    fmt.Printf("config:%+v\n", config)
}

您可以根据您的实际用例定制这个工作示例。更多关于 mapstructuresquash 嵌入结构标签的信息可以找到here

【讨论】:

  • 非常感谢 - 这是一个非常好的解决方案!
猜你喜欢
  • 2016-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-24
  • 2018-04-21
  • 2012-01-28
  • 1970-01-01
  • 2018-04-09
相关资源
最近更新 更多