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

Go语言自定义JSON反序列化:status字段为对象或整数的处理问题

问题分析与解决方案

原代码核心问题

  1. 递归调用死循环:Status的自定义UnmarshalJSON中,反序列化对象时直接使用Status类型,会再次触发自身的UnmarshalJSON方法,导致无限递归栈溢出。
  2. 未处理根节点字段映射:格式二中的title、detail是与status同级的根节点字段,原代码未将这些字段合并到Status结构体中,不符合统一结构体的要求。

修复后的完整代码

package main

import (
	"encoding/json"
	"errors"
)

type ShipmentOrderResponse struct {
	Status Status  `json:"status"`
	Items  *[]Item `json:"items,omitempty"`
}

type Status struct {
	Title    string `json:"title,omitempty"`
	Code     int    `json:"statusCode,omitempty"`
	Instance string `json:"instance,omitempty"`
	Detail   string `json:"detail,omitempty"`
}

type Item struct {
	PropertyPath string `json:"propertyPath"`
	Message      string `json:"message"`
}

// 修复Status的UnmarshalJSON,避免递归
func (s *Status) UnmarshalJSON(d []byte) error {
	// 先尝试反序列化为整数类型(格式二的status字段)
	var code int
	if err := json.Unmarshal(d, &code); err == nil {
		s.Code = code
		return nil
	}

	// 再尝试反序列化为对象类型(格式一的status字段),用匿名结构体绕过自定义Unmarshal
	var obj struct {
		Title    string `json:"title"`
		Code     int    `json:"statusCode"`
		Detail   string `json:"detail"`
		Instance string `json:"instance,omitempty"`
	}
	if err := json.Unmarshal(d, &obj); err != nil {
		return err
	}
	s.Title = obj.Title
	s.Code = obj.Code
	s.Detail = obj.Detail
	s.Instance = obj.Instance
	return nil
}

// 给ShipmentOrderResponse添加自定义Unmarshal,处理两种响应格式
func (sor *ShipmentOrderResponse) UnmarshalJSON(d []byte) error {
	// 尝试匹配格式一:status为对象,包含items字段
	type FormatOne struct {
		Status Status  `json:"status"`
		Items  *[]Item `json:"items,omitempty"`
	}
	var formatOne FormatOne
	if err := json.Unmarshal(d, &formatOne); err == nil {
		sor.Status = formatOne.Status
		sor.Items = formatOne.Items
		return nil
	}

	// 尝试匹配格式二:status为整数,根节点包含title、detail
	type FormatTwo struct {
		Status int    `json:"status"`
		Title  string `json:"title"`
		Detail string `json:"detail"`
	}
	var formatTwo FormatTwo
	if err := json.Unmarshal(d, &formatTwo); err == nil {
		sor.Status.Code = formatTwo.Status
		sor.Status.Title = formatTwo.Title
		sor.Status.Detail = formatTwo.Detail
		sor.Items = nil
		return nil
	}

	return errors.New("invalid response format: neither format matched")
}

关键修复说明

  1. 避免递归:在Status的反序列化中,使用匿名结构体来解析对象类型的status,绕过自定义的UnmarshalJSON方法,彻底解决递归死循环问题。
  2. 统一字段映射:通过ShipmentOrderResponse的自定义UnmarshalJSON,分别适配两种响应格式:
    • 格式一直接映射到目标结构体;
    • 格式二将根节点的title、detail合并到Status字段中,实现两种格式的结构统一。
  3. 简化结构体:移除原ShipmentOrderResponse中的Title、Detail字段,所有状态信息统一存储在Status结构体中,符合目标结构体设计。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 03:07:02