为了账号安全,请及时绑定邮箱和手机立即绑定

解码器无法解组时如何获取 JSON?

解码器无法解组时如何获取 JSON?

Go
森林海 2022-01-10 14:35:48
我正在使用 ajson.Decoder来解码通过网络流传递的 JSON。它工作正常,但是每当有人发送不符合架构的数据时(例如,当结构的字段类型为无符号时发送负整数),它会返回一个错误,并带有一条无法确定违规属性的模糊消息。这使得调试更加困难。有没有办法提取解码器在出错时试图解组的 JSON?这是一个可重现的小片段:package mainimport (    "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)    }}或在操场上:https : //play.golang.org/p/-WdYBkYEzJ
查看完整描述

3 回答

?
波斯汪

TA贡献1811条经验 获得超4个赞

错误中有一些信息,它是类型 *json.UnamrshalTypeError


type UnmarshalTypeError struct {

        Value  string       // description of JSON value - "bool", "array", "number -5"

        Type   reflect.Type // type of Go value it could not be assigned to

        Offset int64        // error occurred after reading Offset bytes

}

您可以获取 json 字符串中的偏移量、reflect.Type被解组到的字段的偏移量以及 Value 的 json 描述。这仍然会给实现自己的解组逻辑的类型带来问题,问题 11858引用了该逻辑


查看完整回答
反对 回复 2022-01-10
?
MMTTMM

TA贡献1869条经验 获得超4个赞

从 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)

    }

}

错误消息字符串也已更改为包含此新信息。


去 1.8:


json: cannot unmarshal number -123 into Go struct field .Bar of type uint32

转到 1.7 及更早版本:


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


查看完整回答
反对 回复 2022-01-10
?
哔哔one

TA贡献1854条经验 获得超8个赞

您可以decode.Token()在Playground和以下(根据您的示例修改)中使用这样的方法获取每个元素、键、值甚至分隔符:


package main


import (

    "bytes"

    "encoding/json"

    "fmt"

)


func main() {

    buff := bytes.NewBufferString(`{"foo": 123, "bar": -123, "baz": "123"}`)

    decoder := json.NewDecoder(buff)


    for {

        t, err := decoder.Token()

        if _, ok := t.(json.Delim); ok {

            continue

        }

        fmt.Printf("type:%11T | value:%5v //", t, t)


        switch t.(type) {

        case uint32:

            fmt.Println("you don't see any uints")

        case int:

            fmt.Println("you don't see any ints")

        case string:

            fmt.Println("handle strings as you will")

        case float64:

            fmt.Println("handle numbers as you will")

        }


        if !decoder.More() {

            break

        }

        if err != nil {

            fmt.Println(err)

        }

    }

}

这将输出


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

您可以根据需要打开类型并处理每个类型。我也展示了一个简单的例子,结果中的每个“//comments”都是基于类型的条件。


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


查看完整回答
反对 回复 2022-01-10
  • 3 回答
  • 0 关注
  • 233 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号