You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)
}

代码说明

  1. 环境控制:通过isStagingEnv变量切换环境,实际项目中可替换为从配置文件或环境变量读取,更灵活
  2. 反射处理:利用reflect包动态遍历结构体字段,根据环境标签匹配JSON键名,避免硬编码
  3. 类型扩展:示例仅处理了string类型字段,可根据实际结构体字段类型,添加int、bool等类型的断言逻辑
  4. 兼容性:保留原json标签,生产环境无需额外修改即可正常使用

运行代码后将得到期望输出:

Production:  { Id: "object-a", Desc: "test" }
Staging:  { Id: "object-a", Desc: "test" }

内容的提问来源于stack exchange,提问作者Kris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 23:55:25