1. 为什么需要重新认识Go的json处理
第一次接触Go语言的json编解码时,大多数开发者都会觉得这简直是世界上最简单的API——json.Marshal和json.Unmarshal两个函数就能搞定一切。但当我真正在线上环境中处理千万级流量的json数据时,才发现这种认知有多么肤浅。
去年我们系统就曾因为一个json解析问题导致整个服务雪崩:某个API返回的字段值意外包含了HTML标签,而我们的解析逻辑没有做任何防护。当这个字段被直接传递给前端时,引发了XSS攻击。事后排查发现,问题根源在于我们过度依赖默认的json编码行为。
提示:Go的json包默认行为是为通用场景设计的,但生产环境中往往需要更精细的控制
Go的encoding/json包确实提供了开箱即用的基础功能,但它的强大之处远不止于此。通过深入理解其底层机制,我们可以实现:
- 高性能的流式处理(适合大json文件)
- 精确的字段类型控制(避免意外类型转换)
- 自定义的编解码逻辑(处理特殊数据结构)
- 安全的HTML字符转义(防止XSS)
- 内存高效的处理方式(降低GC压力)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础编解码的隐藏细节
2.1 Marshal的默认行为陷阱
go复制type User struct {
Name string
Age int
IsAdmin bool
LastSeen time.Time
}
user := User{
Name: "<script>alert(1)</script>",
Age: 30,
IsAdmin: true,
LastSeen: time.Now(),
}
data, err := json.Marshal(user)
这段看似无害的代码至少存在三个潜在问题:
- HTML特殊字符未转义(XSS风险)
- 时间字段默认使用RFC3339格式(可能不符合业务需求)
- 布尔值会原样输出(暴露内部字段名)
解决方案是使用json.MarshalWithOption:
go复制data, err := json.MarshalWithOption(user, json.EscapeHTML, json.DateTimeFormatter(time.Stamp))
2.2 Unmarshal的类型转换暗坑
当json中的数字类型与Go结构体不匹配时,json包会尝试自动转换。这种隐式转换可能导致精度丢失:
go复制var data = []byte(`{"price": 99.99}`)
// 错误示例:float32会丢失精度
type Product struct {
Price floa
