Golang多环境下如何用不同JSON标签实现JSON Unmarshal?
解决多环境JSON字段映射的结构体反序列化问题
问题场景
对接第三方API时,生产(prod)和预发布(staging)环境返回的JSON中,同一业务数据对应不同的自定义键名(比如prod的custom-1对应staging的custom-7)。需要将两种环境的JSON反序列化为同一个结构体,避免因字段增多导致维护多个结构体的高成本。现有代码中staging环境的JSON无法正确反序列化,字段值为空。
解决方案
通过为结构体编写自定义UnmarshalJSON方法,结合环境标识动态选择对应的字段标签(json或jsonStaging)完成映射。核心步骤如下:
- 定义环境标识,区分当前运行环境
- 在自定义反序列化方法中,先将JSON解析为通用map,再通过反射遍历结构体字段,根据环境标签从map中取值并赋值
完整代码实现
package main import ( "encoding/json" "fmt" "reflect" ) // 环境标识,实际项目可从环境变量读取(如os.Getenv("ENV")) var isStagingEnv = false type jsonObj struct { Id string `json:"custom-1" jsonStaging:"custom-7"` Desc string `json:"custom-2" jsonStaging:"custom-8"` } func (i *jsonObj) UnmarshalJSON(data []byte) error { // 先把JSON解析成通用map var rawMap map[string]interface{} if err := json.Unmarshal(data, &rawMap); err != nil { return err } // 获取结构体的反射实例 val := reflect.ValueOf(i).Elem() typ := val.Type() // 遍历所有字段 for idx := 0; idx < typ.NumField(); idx++ { field := typ.Field(idx) valField := val.Field(idx) // 根据环境选择对应标签 tagKey := field.Tag.Get("json") if isStagingEnv { tagKey = field.Tag.Get("jsonStaging") } if tagKey == "" { continue } // 从map中取值并赋值给结构体字段 if rawVal, ok := rawMap[tagKey]; ok { switch field.Type.Kind() { case reflect.String: if strVal, ok := rawVal.(string); ok { valField.SetString(strVal) } // 可按需扩展int、bool等其他类型的处理逻辑 } } } return nil } func (i jsonObj) String() string { return fmt.Sprintf(`{ Id: "%s", Desc: "%s" }`, i.Id, i.Desc) } func main() { var jsonProd = `{ "custom-1": "object-a", "custom-2": "test" }` var jsonStaging = `{ "custom-7": "object-a", "custom-8": "test" }` var jsonObjProd jsonObj // 生产环境反序列化 isStagingEnv = false json.Unmarshal([]byte(jsonProd), &jsonObjProd) fmt.Println("Production: ", jsonObjProd) var jsonObjStaging jsonObj // 预发布环境反序列化 isStagingEnv = true json.Unmarshal([]byte(jsonStaging), &jsonObjStaging) fmt.Println("Staging: ", jsonObjStaging) }
代码说明
- 环境控制:通过
isStagingEnv变量切换环境,实际项目中可替换为从配置文件或环境变量读取,更灵活 - 反射处理:利用
reflect包动态遍历结构体字段,根据环境标签匹配JSON键名,避免硬编码 - 类型扩展:示例仅处理了string类型字段,可根据实际结构体字段类型,添加int、bool等类型的断言逻辑
- 兼容性:保留原
json标签,生产环境无需额外修改即可正常使用
运行代码后将得到期望输出:
Production: { Id: "object-a", Desc: "test" } Staging: { Id: "object-a", Desc: "test" }
内容的提问来源于stack exchange,提问作者Kris
相关产品推荐
相关产品推荐

