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

huangapple go评论214阅读模式
英文:

How to detect if received JSON has unknown fields

问题

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

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

接收到的JSON:

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

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

英文:

I'm trying to find some way to prohibit arbitrary JSON keys and fields in Go. For now, if I send payload with undeclared fields in struct, the service will work normally and will map the entity described fields (likejson:"id,omitempty").
For example:

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

Received JSON:

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

Can anybody help me to find the way of tracking unknown field in payload? I need to return an error in that case.

答案1

得分: 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。关于这方面的更多信息,请参考这里:https://stackoverflow.com/questions/23840362/how-to-read-struct-field-decorators

英文:

Update:

you might want to use DisallowUnknownFields() read for more info


old answer:

There is a proposal for golang 1.9 on this: proposal: some way to reject unknown fields in encoding/json.Decoder

Till then you could try something like this playground (code also below).
The key idea is to parse the json into a map[string]interface{} and then work with the keys. This will of course get much more complicated if you have nested structs.

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
}

You can even get rid of the variable allowedFooKeys by getting the allowed keys directly from the Foo struct using reflect. For more info on that see here: https://stackoverflow.com/questions/23840362/how-to-read-struct-field-decorators

答案2

得分: 0

自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

英文:

Since Go 1.10, the JSON decoder provides the DisallowUnknownFields() option for this use case.

func StrictUnmarshal(data []byte, v interface{}) error {
    dec := json.NewDecoder(bytes.NewReader(data))
    dec.DisallowUnknownFields()
    return dec.Decode(v)
}

You can find a full working example here:

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

huangapple
  • 本文由 发表于 2017年7月12日 18:36:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/45055327.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定