解码器解组失败时如何获取JSON?

解码器解组失败时如何获取JSON?,json,go,Json,Go,我正在使用json.Decoder对通过网络流传递的json进行解码。它工作正常,但每当有人发送不符合模式的数据(例如,当结构的字段类型为无符号时发送负整数)时,它就会返回一个错误,并显示一条模糊消息,该消息不会精确指出有问题的属性。这使得调试更加困难 有没有办法提取解码器出错时试图解组的JSON?下面是一个可复制的小片段: package main import ( "bytes" "fmt" "encoding/json" ) func main() {

我正在使用
json.Decoder
对通过网络流传递的json进行解码。它工作正常,但每当有人发送不符合模式的数据(例如,当结构的字段类型为无符号时发送负整数)时,它就会返回一个错误,并显示一条模糊消息,该消息不会精确指出有问题的属性。这使得调试更加困难

有没有办法提取解码器出错时试图解组的JSON?下面是一个可复制的小片段:

package main

import (
    "bytes"
    "fmt"
    "encoding/json"
)

func main() {
    buff := bytes.NewBufferString("{\"bar\": -123}")
    decoder := json.NewDecoder(buff)

    var foo struct{
        Bar uint32
    }
    if err := decoder.Decode(&foo); err != nil {
        fmt.Println(err)
        fmt.Println("TODO: how to get JSON that caused this error?")
    } else {
        fmt.Println(foo.Bar)
    }
}

或者在操场上:

错误中包含一些信息,类型为


您可以获取json字符串中的偏移量、要解组的字段的
reflect.Type
,以及值的json描述。对于实现自己的解组逻辑的类型来说,这仍然会带来问题,解组逻辑由

引用。您可以使用
decode.Token()
获取每个元素、键、值,甚至分隔符,如下所示(根据您的示例修改):

这将输出

type:     string | value:  foo //handle strings as you will
type:    float64 | value:  123 //handle numbers as you will
type:     string | value:  bar //handle strings as you will
type:    float64 | value: -123 //handle numbers as you will
type:     string | value:  baz //handle strings as you will
type:     string | value:  123 //handle strings as you will
您可以打开类型并根据需要处理每个类型。我也展示了一个简单的例子,结果中的每个“//注释”都是基于类型的条件


您还将注意到,每个数字的类型都是float64,尽管它们可以放在int中,甚至在“foo”值的情况下可以放在uint中,我在开关中检查这些类型,但它们从未被使用过。您必须提供自己的逻辑,以便将float64值转换为您想要的类型(如果可以),并处理不会转换为特殊情况、错误或任何您想要的类型。

从Go 1.8开始,这现在是可能的。
UnmarshalTypeError
类型现在包含
Struct
Field
值,这些值提供了导致类型不匹配的结构和字段的名称

package main

import (
    "bytes"
    "fmt"
    "encoding/json"
)

func main() {
    buff := bytes.NewBufferString("{\"bar\": -123}")
    decoder := json.NewDecoder(buff)

    var foo struct{
        Bar uint32
    }
    if err := decoder.Decode(&foo); err != nil {
        if terr, ok := err.(*json.UnmarshalTypeError); ok {
                fmt.Printf("Failed to unmarshal field %s \n", terr.Field)
        } else {
            fmt.Println(err)
        }
    } else {
        fmt.Println(foo.Bar)
    }
}
错误消息字符串也已更改为包含此新信息

Go 1.8:

json: cannot unmarshal number -123 into Go struct field .Bar of type uint32
Go 1.7及更早版本:

json: cannot unmarshal number -123 into Go value of type uint32

Bar
是否必须是
uint32
?有没有什么原因使您不能使用
int
?您是否尝试过或?这是另一个例子,说明为什么您不应该对任何可能为负值的对象使用无符号值,即使负值不正确。使用int、int32或int64并用另一种方式验证“架构”。@JimB它是
uint32
,因为负值不是有效的输入。我希望解组出错,因为它应该出错;数据无效。我只想让它具体说明失败的地方,这样我就可以记录有意义的数据进行调试。你的解决方案在我给出的例子中确实有效;但是如果JSON属性是一个字符串/数组/对象而不是一个int怎么办?负值可能对您的模式无效,但它们是有效的JSON数字。无符号值应保留用于按位或模运算,否则使用有符号值。
json: cannot unmarshal number -123 into Go struct field .Bar of type uint32
json: cannot unmarshal number -123 into Go value of type uint32