解组字符串时在输入字节 0 处输入非法 base64 数据 json

Go illegal base64 data at input byte 0 when unmarshalling a string json

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

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

这是一个有效的 json 字符串(Go 省略了前导引号和尾引号)但是我在解组时遇到了这个错误。 illegal base64 data at input byte 0

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}