如何检测接收到的JSON是否具有未知字段

4

我正在尝试找到一种方法来禁止Go中任意的JSON键和字段。目前,如果我发送包含结构体中未声明字段的负载,服务将正常工作,并映射实体描述的字段(例如json:“id,omitempty”)。例如:

type Foo struct {
    Bar         int        `json:"id,omitempty"`
}

收到的 JSON:

{
  "id": 12,
  "hey": "hey"
}

有没有人能帮我找到在有效负载中跟踪未知字段的方法?在这种情况下,我需要返回一个错误。


所以你的意思是当像你例子中的"hey"这样的字段作为有效载荷的一部分发送时,你想要抛出一个错误? - kkaosninja
@kkaosninja,是的 - Jeff
顺便提一句,在 Java 中我们会“抛出”错误,但在 Golang 中我们只需要“返回”它们 :) - Nevermore
2个回答

6

更新:

您可能希望使用DisallowUnknownFields()阅读更多信息


旧答案:

有一个关于golang 1.9的提案:proposal: some way to reject unknown fields in encoding/json.Decoder

在那之前,您可以尝试像playground中的代码(下面也有代码)。关键思想是将json解析为map[string]interface{},然后使用键。当然,如果你有嵌套结构,这会变得更加复杂。

package main

import (
    "encoding/json"
    "fmt"
)

type Foo struct {
    Bar int `json:"id,omitempty"`
}
var allowedFooKeys = []string{"id"}

func main() {
    b := []byte(`{
      "id": 12,
      "hey": "hey"
    }`)
    m := map[string]interface{}{}

    if err := json.Unmarshal(b, &m); err != nil {
        panic(err)
    }

    for k, _ := range m {
        if !keyExists(k, allowedFooKeys) {
            fmt.Println("Disallowed key in JSON:", k)
        }
    }
}

func keyExists(key string, keys []string) bool {
    for _, k := range keys {
        if k == key {
            return true
        }
    }
    return false
}

您甚至可以通过使用反射从Foo结构中直接获取允许的键来摆脱变量allowedFooKeys。有关更多信息,请参见此处:如何读取结构字段修饰符?

1
自Go 1.10以来,JSON解码器为此用例提供了DisallowUnknownFields()选项。
func StrictUnmarshal(data []byte, v interface{}) error {
    dec := json.NewDecoder(bytes.NewReader(data))
    dec.DisallowUnknownFields()
    return dec.Decode(v)
}

您可以在此处找到一个完整的工作示例:

https://go.dev/play/p/HoGDIt8nJB7


请注意,如果在 JSON 后面有垃圾字符,上述代码可能会出错。请参阅此处获取更多信息 - Mitar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接