问题描述
我将我的数据存储在一个 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)
_,"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
。
尝试将 Hash
和 PrevHash
解组为 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}