json.valid只能验证utf-8编码的原始json字节流或字符串,不支持直接校验结构体或map;需先用json.marshal序列化,再校验语法合法性,且需预处理bom头、限制http请求体大小。

json.Valid 为什么不能直接验证结构体或 map
json.Valid 只接受 []byte 或 string 类型的原始 JSON 文本,它不做任何 Go 类型转换,也不检查字段名是否合法、是否符合某个 struct tag。传入一个已序列化的 map[string]interface{} 或 struct 实例会编译报错——因为类型不匹配。
常见错误是试图这样写:json.Valid(myStruct) 或 json.Valid(mapData),结果直接失败。必须先用 json.Marshal 转成字节流,再交给 json.Valid:
data, _ := json.Marshal(map[string]string{"name": "alice"})
if json.Valid(data) {
// ✅ 正确
}
json.Valid 和 json.Unmarshal 的验证强度差异
json.Valid 只做语法校验:括号配对、引号闭合、字符串转义、数字格式等基础合法性。它不关心字段是否存在、类型是否匹配、是否多余字段——这些都留给 json.Unmarshal 处理。
例如:"{"age": 25, "city": null}" 能过 json.Valid,但若目标 struct 中 City 是 string 类型,Unmarshal 就会报错 json: cannot unmarshal null into Go struct field ... of type string。
-
json.Valid:快、轻量、适合前置过滤(比如 API 入参预检) -
json.Unmarshal:全量语义校验,适合真正解析和绑定 - 两者不是替代关系,而是分工:先
Valid快速筛掉明显非法字符串,再Unmarshal做业务级校验
注意 UTF-8 编码和 BOM 头导致的验证失败
json.Valid 要求输入严格为 UTF-8 编码,且不能含 BOM(Byte Order Mark)。从文件读取或前端 POST 过来的 JSON 字符串如果带 \uFEFF 开头,json.Valid 会直接返回 false,不报错也不提示原因。
实操建议:
- 用
bytes.TrimPrefix([]byte(s), []byte("\uFEFF"))预处理字符串 - 或在读取文件时用
bufio.NewReader+strings.TrimPrefix清除 BOM - 调试时可打印前几个字节:
fmt.Printf("%x", []byte(s)[:4]),看到efbbbf就是 UTF-8 BOM
json.Valid 在 HTTP 请求体中的典型用法
接收 io.ReadCloser(如 req.Body)时,不能直接传给 json.Valid——它只认 string 或 []byte。必须先读取全部内容,再验证:
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "read body failed", http.StatusBadRequest)
return
}
if !json.Valid(body) {
http.Error(w, "invalid JSON", http.StatusBadRequest)
return
}
注意两点:
- 务必限制
body大小(比如用http.MaxBytesReader),否则恶意构造超大字符串会导致内存耗尽 -
io.ReadAll后r.Body已关闭,不能再重复读;后续要解析需用json.Unmarshal(body, &v),别再调json.NewDecoder(r.Body)
验证通过后,body 可复用,避免二次读取开销——这点容易被忽略,尤其在性能敏感服务中。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











