Golang读取及使用环境变量

JSON
HTTPMySQL
SERVER_PORT=80 # HTTP服务端口
MYSQL_HOST=mysql.domain.local # MySQL主机地址
MYSQL_PORT=3306 # MySQL端口
MYSQL_USER=jack # MySQL用户名
MYSQL_PASSWD=Jk_220107 # MySQL密码 
MYSQL_INSTANCE=test # MySQL数据库名

接下来通过代码与配置文件读取的异同。

读取系统环境变量

GoAPI
func Setenv(key, value string) error // 设置环境变量,失败时返回error
func Unsetenv(key string) error // 取消设置环境变量,失败时返回error
func Getenv(key string) string // 获取环境变量,不存在时返回空字符串
func LookupEnv(key string) (string, bool) // 查询环境变量,存在时bool返回true且string有值,否则为false且string为空
func ExpandEnv(s string) string // 替换字符串中的${var}或$var为当前的系统环境变量,不存在则替换为空
func Clearenv() // 清除环境变量
GetenvLookupEnv
package main
​
import (
    "fmt"
    "os"
    "net/http"
)
​
// DSN: Data Source Name
func getDSN() string {
/* Getenv也或等价换成LookupEnv调用
    dbHost := os.Getenv("MYSQL_HOST")
    dbPort := os.Getenv("MYSQL_PORT")
    dbUser := os.Getenv("MYSQL_USER")
    dbPasswd := os.Getenv("MYSQL_PASSWD")
    dbName := os.Getenv("MYSQL_INSTANCE")
    if len(dbHost) != 0 && len(dbPort) != 0 && len(dbUser) != 0 && len(dbPasswd) != 0 && len(dbName) != 0 {    
        return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", dbUser, dbPasswd, dbHost, dbPort, dbName)
    }
*/
    if dbHost, ok := os.LookupEnv("MYSQL_HOST"); ok {
        if dbPort, ok := os.LookupEnv("MYSQL_PORT"); ok {
            if dbUser, ok := os.LookupEnv("MYSQL_USER"); ok {
                if dbPasswd, ok := os.LookupEnv("MYSQL_PASSWD"); ok {
                    if dbName, ok := os.LookupEnv("MYSQL_INSTANCE"); ok {
                        return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", dbUser, dbPasswd, dbHost, dbPort, dbName)
                    }
                }
            }
        }
    }
    return ""
}
​
func homeHandler(rw http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(rw, "Hello, world!")
}
​
func main() {
    http.HandleFunc("/", homeHandler)
    svrPort := osGetenv("SERVER_PORT")
    if len(svrPort) != 0 {
        http.ListenAndServe(":" + svrPort, nil)
    }
}

由于环境变量散落在代码里,且无法动态修改或增减,通过配置文件加载可以更加灵活些。

通过JSON文件配置的环境变量

config.json
{
    "server_port": ${SERVER_PORT},
    "mysql_host": "${MYSQL_HOST}",
    "mysql_port": ${MYSQL_PORT},
    "mysql_user": "${MYSQL_USER}",
    "mysql_passwd": "${MYSQL_PASSWD}",
    "mysql_instance": "${MYSQL_INSTANCE}"
}

代码实现如下:

package main
​
import (
    "fmt"
    "os"
    "net/http"
    "io/ioutil"
    "encoding/json"
)
​
type svrConfig struct {
    ServerPort    int    `json:"server_port"`
    MySQLHost     string `json:"mysql_host"`
    MySQLPort     int    `json:"mysql_host"`
    MySQLUser     string `json:"mysql_host"`
    MySQLPasswd   string `json:"mysql_host"`
    MySQLInstance string `json:"mysql_instance"`
}
​
// DSN: Data Source Name
func getDSN(dbHost string, dbPort int, dbUser string, dbPasswd string, dbName string) string {
    return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", dbUser, dbPasswd, dbHost, dbPort, dbName)
}
​
func homeHandler(rw http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(rw, "Hello, world!")
}
​
func main() {
    cfg := svrConfig{}
    if orgData, err := ioutil.ReadFile('config.json'); err != nil {
        panic(err.Error())
    } else {
        data := os.ExpandEnv(string(orgData))
        if err := json.Unmarshal([]byte(data), cfg); err != nil {
            panic(err.Error())
        }
        // TODO: dsn for mysql connection
        dsn := getDSN(cfg.MySQLHost, cfg.MySQLPort, cfg.MySQLUser, cfg.MySQLPasswd, cfg.MySQLInstance)
        fmt.Fprintf("dsn: %s.", dsn)
        http.HandleFunc("/", homeHandler)
        http.ListenAndServe(":" + cfg.SeverPort, nil) 
    }
}
os.Getenvos.LookupEnvos.ExpandEnvos.ExpandEnvyaml
$var${var}${test:-abc}bash