用 json.newdecoder 解码到结构体,并在 decode 前调用 disallowunknownfields()。如果输入只允许一个 json 对象,再尝试读取一次并要求得到 io.eof,以拦截尾部多余内容。

用结构体定义允许的字段
保存为 main.go。这里限制输入为一个非空 JSON 对象。
package main
import (
"encoding/json"
"fmt"
"io"
"strings"
)
type CreateUser struct {
Name string `json:"name"`
}
func decode(input io.Reader) (*CreateUser, error) {
decoder := json.NewDecoder(input)
decoder.DisallowUnknownFields()
var user *CreateUser
if err := decoder.Decode(&user); err != nil {
return nil, fmt.Errorf("读取对象: %w", err)
}
if user == nil {
return nil, fmt.Errorf("需要 JSON 对象")
}
var extra json.RawMessage
if err := decoder.Decode(&extra); err != io.EOF {
return nil, fmt.Errorf("对象后只允许空白")
}
return user, nil
}
func main() {
user, err := decode(strings.NewReader(`{"name":"Lin"}`))
fmt.Println(user, err)
}
运行 go run main.go,预期输出 &{Lin}
验证未知字段和尾随对象
在 main 中追加下面的循环。
for _, input := range []string{
`{"name":"Lin","nmae":"typo"}`,
`{"name":"Lin"} {"name":"Yu"}`,
`null`,
} {
_, err := decode(strings.NewReader(input))
fmt.Println(err)
}预期三行均报错,依次指出未知字段、多余内容和需要对象。
补上业务必填校验
在 decode 的空对象检查之后,可加上这个判断。
if strings.TrimSpace(user.Name) == "" {
return nil, fmt.Errorf("name 不能为空")
}未知字段检查与必填检查各有作用。若契约还要求拒绝重复键,需要额外验证,因为该选项只控制未知字段。


















