英文:
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:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论