了解环境变量以及在 Golang 应用程序中使用它们的不同方法。
开始之前
本教程假定你具有:
- 对 Go 语言的基本了解
- 系统上安装了最新 Golang 版本
- 几分钟的时间
在本文中,我们将了解环境变量以及为什么要使用它们。并且将使用内置和第三方包在 Go 应用程序中访问它们。
什么是环境变量?
环境变量是系统级的键-值对,正在运行的进程可以访问它。这些通常用于使同一程序在不同的部署环境(例如 PROD, DEV 或 TEST)中表现不同。在环境中存储配置是 twelve-factor 应用程序的原理之一。它使应用程序具有可移植性。
为什么要使用环境变量
git
永远不要忘记在 .gitignore 中包含环境变量文件
内置操作系统包
您不需要任何外部程序包即可访问 Golang 中的环境变量,并且可以使用标准库 os
包来实现。以下是与环境变量有关的函数及其用途的列表。
-
os.Setenv()
设置环境值的值。 -
os.Getenv()
获取指定键对应的环境变量值。 -
os.Unsetenv()
删除指定键命名对应的单个环境值,如果我们再尝试使用os.Getenv()
来获取该环境值,将返回一个空值。 -
os.ExpandEnv
根据环境变量的值替换字符串中的${var}
或$var
。如果不存在任何环境变量,则将使用空字符串替换它。 -
os.LookupEnv()
获取指定键对应的环境变量值。如果系统中不存在该变量,则返回值将为空,并且布尔值将为 false。否则,它将返回值(可以为空),并且布尔值为 true。
如果不存在环境变量,则 os.Getenv() 将返回一个空字符串,使用 LookupEnv 来区分空值和未设置值。
现在,让我们在代码中使用上述所有函数。在一个空文件夹中创建一个 main.go 文件。
package main import ( "fmt" "os" ) func main() { // Set Environment Variables os.Setenv("SITE_TITLE", "Test Site") os.Setenv("DB_HOST", "localhost") os.Setenv("DB_PORT", "27017") os.Setenv("DB_USERNAME", "admin") os.Setenv("DB_PASSWORD", "password") os.Setenv("DB_NAME", "testdb") // Get the value of an Environment Variable host := os.Getenv("SITE_TITLE") port := os.Getenv("DB_HOST") fmt.Printf("Site Title: %s, Host: %s\n", host, port) // Unset an Environment Variable os.Unsetenv("SITE_TITLE") fmt.Printf("After unset, Site Title: %s\n", os.Getenv("SITE_TITLE")) //Checking that an environment variable is present or not. redisHost, ok := os.LookupEnv("REDIS_HOST") if !ok { fmt.Println("REDIS_HOST is not present") } else { fmt.Printf("Redis Host: %s\n", redisHost) } // Expand a string containing environment variables in the form of $var or ${var} dbURL := os.ExpandEnv("mongodb://${DB_USERNAME}:${DB_PASSWORD}@$DB_HOST:$DB_PORT/$DB_NAME") fmt.Println("DB URL: ", dbURL) }
下面是我们在终端中执行 go run main.go
的输出:
go run main.go // output Site Title: Test Site, Host: localhost After unset, Site Title: 27017 REDIS_HOST is not present DB URL: mongodb://admin:password@localhost:27017/testdb
还有两个函数 os.Clearenv
和 os.Environ()
,让我们在单独的程序中使用它们。
os.Clearenv os.Environ()
package main import ( "fmt" "os" "strings" ) func main() { // Environ returns a slice of string containing all the environment variables in the form of key=value. for _, env := range os.Environ() { // env is envPair := strings.SplitN(env, "=", 2) key := envPair[0] value := envPair[1] fmt.Printf("%s : %s\n", key, value) } // Delete all environment variables os.Clearenv() fmt.Println("Number of environment variables: ", len(os.Environ())) }
上面的函数将列出系统中所有可用的环境变量,包括 NAME
和 DB_HOST
。一旦运行 os.Clearenv()
,它将清除正在运行的进程的所有环境变量。
GoDotEnv 包
Ruby dotenv 项目启发了 GoDotEnv
包,它从 .env
文件加载环境变量。
让我们创建一个 .env
文件,其中包含所有配置。
# .env file # This is a sample config file SITE_TITLE=Test Site DB_HOST=localhost DB_PORT=27017 DB_USERNAME=admin DB_PASSWORD=password DB_NAME=testdb
然后在 main.go 文件中,我们将使用 godotenv 加载环境变量。
我们也可以一次加载多个 env 文件。godotenv 还支持 YAML。
// main.go package main import ( "fmt" "log" "os" "github.com/joho/godotenv" ) func main() { // load .env file from given path // we keep it empty it will load .env from current directory err := godotenv.Load(".env") if err != nil { log.Fatalf("Error loading .env file") } // getting env variables SITE_TITLE and DB_HOST siteTitle := os.Getenv("SITE_TITLE") dbHost := os.Getenv("DB_HOST") fmt.Printf("godotenv : %s = %s \n", "Site Title", siteTitle) fmt.Printf("godotenv : %s = %s \n", "DB Host", dbHost) }
打开终端并运行 main.go
:
go run main.go // output godotenv : Site Title = Test Site godotenv : DB Host = localhost
Viper 包
Viper 是 Go 应用程序的配置的完整解决方案。它旨在在应用程序中工作,并且可以处理所有类型的配置需求和格式。
Viper
支持多种文件格式来加载环境变量,例如,从 JSON,TOML,YAML,HCL,envfile 和 Java 属性配置文件(properties)中读取。因此,在此示例中,我们将研究如何从 YAML 文件中加载环境变量。
YAML 是一种人类可读的数据序列化语言。它通常用于配置文件和用于存储或传输数据的应用程序。
让我们在一个空文件夹中创建 config.yaml 和 main.go。
# config.yaml SITE: TITLE: Test Site DB: HOST: "localhost" PORT: "27017" USERNAME: "admin" PASWORD: "password" NAME: "testdb"
在下面的代码中,我们使用 Viper 从 config.yaml 中加载环境变量。我们可以从所需的任何路径加载配置文件。如果配置文件中没有任何环境变量,我们还可以为任何环境变量设置默认值。
// main.go package main import ( "fmt" "log" "os" "github.com/spf13/viper" ) func main() { // Set the file name of the configurations file viper.SetConfigName("config") // Set the path to look for the configurations file viper.AddConfigPath(".") // Enable VIPER to read Environment Variables viper.AutomaticEnv() viper.SetConfigType("yml") if err := viper.ReadInConfig(); err != nil { fmt.Printf("Error reading config file, %s", err) } // Set undefined variables viper.SetDefault("DB.HOST", "127.0.0.1") // getting env variables DB.PORT // viper.Get() returns an empty interface{} // so we have to do the type assertion, to get the value DBPort, ok := viper.Get("DB.PORT").(string) // if type assert is not valid it will throw an error if !ok { log.Fatalf("Invalid type assertion") } fmt.Printf("viper : %s = %s \n", "Database Port", DBPort) }
打开终端并运行 main.go
:
go run main.go // output viper : Database Port = 27017
结论
使用环境变量是在我们的应用程序中处理配置的绝佳方法。总体而言,它为您提供了轻松的配置,更好的安全性,多个部署环境以及更少的生产错误。
现在您可以在 go 应用程序中管理环境变量,并且可以在我们的 Github Repo
上找到本教程中使用的完整代码。
原文链接: https://www.loginradius.com/engineering/blog/environment-variables-in-golang/
作者:Puneet Singh
编译:polarisxu