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 验证器。
常见错误
- 忽略
Marshal、Unmarshal或Decode返回的错误。 - 误解
null、缺失字段和 Go 零值的区别。 - 用浮点数承载金额或精确 ID。
- 对不可信请求体无限制读取。
- 以为
DisallowUnknownFields永远是兼容性更好的默认值。
小结
- struct tag 定义外部字段契约,导出规则决定默认可见性。
- 流式输入应限制大小,数字精度必须显式设计。
- 解码成功不代表业务校验成功。