跳到主要内容

JSON 编解码

encoding/json 负责 JSON 与 Go 值之间的转换,但不会替业务判断字段是否完整、范围是否有效或请求是否授权。

Marshal 与 Unmarshal

package main

import (
"encoding/json"
"fmt"
)

type User struct {
ID int `json:"id"`
Name string `json:"name"`
}

func main() {
data, err := json.Marshal(User{ID: 1, Name: "Ada"})
if err != nil {
panic(err)
}

var user User
if err := json.Unmarshal(data, &user); err != nil {
panic(err)
}
fmt.Println(string(data), user.Name)
}

导出字段才会参与默认编解码;标签控制外部字段名、忽略字段和 omitempty 行为。omitempty 会把零值省略,不等于“字段从未出现”,需要区分时使用指针或自定义类型。

外部输入与流式处理

对 HTTP 请求或文件流使用 json.Decoder,并限制读取大小。可以调用 DisallowUnknownFields 发现拼写错误,但这会降低向前兼容性,应按接口契约选择。解码到 any 时 JSON 数字默认是 float64;金额和大整数应使用整数最小单位、json.Number 或明确的 decimal 方案。

解码成功后仍需校验必填字段、长度、范围和相互关系。不要把静态 struct 当作运行时 schema 验证器。

常见错误

  • 忽略 MarshalUnmarshalDecode 返回的错误。
  • 误解 null、缺失字段和 Go 零值的区别。
  • 用浮点数承载金额或精确 ID。
  • 对不可信请求体无限制读取。
  • 以为 DisallowUnknownFields 永远是兼容性更好的默认值。

小结

  • struct tag 定义外部字段契约,导出规则决定默认可见性。
  • 流式输入应限制大小,数字精度必须显式设计。
  • 解码成功不代表业务校验成功。