json - 解码字符串 json 时,在输入字节 0 处出现非法 base64 数据

标签 json go marshalling

我将我的数据存储在一个 redis 数据库中,当我请求它时,我得到了一个有效的 json。 json 看起来像这样:

{"Data":"hi","Hash":"000f7dcfca98450a0f405384db3878c1956cb98309e63cf2d0a963cff9f17260","PrevHash":"000daf177434acd55a3284787b793a3453c3d70eacdb9a84f5faed43adb2ff58","Nonce":8504,"TimeStamp":1611498968}

这是一个有效的 json 字符串(Go 省略了前导引号和尾引号),但我在解码时收到此错误。 输入字节 0 处的非法 base64 数据

err = json.Unmarshal([]byte(item), &block)

type Block struct {
    Data      []byte
    Hash      []byte
    PrevHash  []byte
    Nonce     int
    TimeStamp int64
}

func (chain *BlockChain) AddBlock(data string) {
    var lastHash []byte

    item, err := chain.Database.Get(ctx, "lastHash").Result()
    Handle(err)
    lastHash = []byte(item)
    newBlock := createBlock(data, lastHash)

    _, err = chain.Database.Set(ctx, StrHash(newBlock.Hash), newBlock, 0).Result()
    Handle(err)
    _, err = chain.Database.Set(ctx, "lastHash", newBlock.Hash, 0).Result()
}

func (chain *BlockChain) Iterator() *BlockChainIterator {
    return &BlockChainIterator{
        CurrentHash: chain.LastHash,
        Database:    chain.Database,
    }
}

func (iterator *BlockChainIterator) Next() *Block {
    var block *Block

    item, err := iterator.Database.Get(ctx, StrHash(iterator.CurrentHash)).Result()
    
    Handle(err)
    err = json.Unmarshal([]byte(item), &block)

    Handle(err)
    iterator.CurrentHash = block.PrevHash

    return block

}

// -----------------
// Utility Functions
// -----------------

// TODO: Think about this. Wouldn't it be better to store everything as strings rather than converting it?
type jsonBlock struct {
    Data      string
    Hash      string
    PrevHash  string
    Nonce     int
    TimeStamp int64
}

// This function gets called automatically by go-redis
func (b *Block) MarshalBinary() ([]byte, error) {
    jb := jsonBlock{
        Data:      string(b.Data),
        Hash:      StrHash(b.Hash),
        PrevHash:  StrHash(b.PrevHash),
        Nonce:     b.Nonce,
        TimeStamp: b.TimeStamp,
    }
    return json.Marshal(jb)
}

最佳答案

JSON 中的 Hash 值(以及 PrevHash)不是数据的 Base64 编码形式,而是十六进制表示。如果您尝试将其解码为 []byte 类型的 Go 值,encoding/json包假定并尝试将其解释为 Base64 编码数据。

Data 字段也是如此:它应该是 Go 类型 string 因为它不是 Base64 编码形式,所以将其更改为 string.

尝试将 HashPrevHash 解码为 string 类型的字段,并使用 hex.DecodeString() 进行十六进制解码.

您可以实现一个自定义解码器来自动执行此操作。

一种方便的方法是创建一个 HexData 类型,它是一个 []byte 但从十六进制字符串解码:

type HexData []byte

func (h *HexData) UnmarshalJSON(data []byte) error {
    var s string
    if err := json.Unmarshal(data, &s); err != nil {
        return err
    }
    decoded, err := hex.DecodeString(s)
    if err != nil {
        return err
    }
    *h = HexData(decoded)
    return nil
}

使用它:

type Block struct {
    Data      string
    Hash      HexData
    PrevHash  HexData
    Nonce     int
    TimeStamp int64
}

func main() {
    var b Block
    if err := json.Unmarshal([]byte(src), &b); err != nil {
        panic(err)
    }
    fmt.Printf("%+v\n", b)
}

输出(在 Go Playground 上尝试):

{Data:hi Hash:[0 15 125 207 202 152 69 10 15 64 83 132 219 56 120 193 149 108 185 131 9 230 60 242 208 169 99 207 249 241 114 96] PrevHash:[0 13 175 23 116 52 172 213 90 50 132 120 123 121 58 52 83 195 215 14 172 219 154 132 245 250 237 67 173 178 255 88] Nonce:8504 TimeStamp:1611498968}

关于json - 解码字符串 json 时,在输入字节 0 处出现非法 base64 数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65872616/

相关文章:

javascript - 获取 JSON 数据 - 这里是新手

unit-testing - 在 Visual Studio Code 中调试 Go 测试

c# - 如何使用编码绑定(bind) Xamarin iOS Obj-C 库

c++ - 将字符串从 C++ 传递到 C++/CLI

mysql - jQuery 日期选择器,禁用来自 MYSQL 的日期

json - 将 JSON 字符串反序列化为 Haxe 中的类实例

javascript - 实时流程图不适用于 JSON

xml - 接口(interface)和编码/xml Unmarshal

go - 在没有结构的情况下解码未知的 JSON 字段

c# - 我如何将 C# string[] 编码(最好在 SWIG 中)到 C++ string*?