我有一个自定义类型(哈希[64] byte),我正在尝试实现MarshalJSON / UnmarshalJSON,以使其在JSON中作为base64字符串进行编码/解码。相反,我在一开始就收到有关无效字符的错误。
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
)
type Hash [64]byte
func FromString(data string) (Hash, error) {
decoded, err := base64.StdEncoding.DecodeString(string(data))
if err != nil {
return Hash{}, err
}
hash := Hash{}
for index := 0; index < 64; index++ {
hash[index] = decoded[index]
}
return hash, nil
}
func (hash Hash) String() string {
return base64.StdEncoding.EncodeToString([]byte(hash[:64]))
}
func (hash Hash) MarshalJSON() ([]byte, error) {
return []byte(hash.String()), nil
}
func (hash *Hash) UnmarshalJSON(data []byte) error {
decoded, err := FromString(string(data))
if err != nil {
return err
}
for index := 0; index < 64; index++ {
hash[index] = decoded[index]
}
return nil
}
func main() {
type TestStructure struct {
Hash Hash
Type string
}
object := TestStructure{
Hash: Hash{0xbd, 0xfe, 0xe0, 0xb1, 0x6c, 0xff, 0xb4, 0x51, 0x4c, 0x7b, 0xed, 0x33, 0xc1, 0x6d, 0xac, 0x5e, 0x80, 0x51, 0xec, 0xcb, 0x31, 0x21, 0x8c, 0x54, 0xb, 0xec, 0xbc, 0x7e, 0xbf, 0x4a, 0xce, 0x92, 0x3b, 0xcb, 0xf8, 0xdd, 0x82, 0x45, 0x34, 0xae, 0x58, 0x5, 0x3a, 0x7b, 0x18, 0xdd, 0x30, 0x5c, 0x7e, 0xed, 0xc9, 0xaa, 0x1e, 0x3a, 0x9a, 0x95, 0x30, 0xc3, 0x6b, 0xf8, 0xf9, 0x92, 0x43, 0xc6},
Type: "I'm a type",
}
data, err := json.Marshal(object)
fmt.Println(data, err)
}
我遇到以下错误:
$ go run hash.go
[] json: error calling MarshalJSON for type main.Hash: invalid character 'v' looking for beginning of value
我在做什么错了?
答案 0 :(得分:2)
您的MarshalJSON
方法需要在返回的值中包含引号,否则您将得到无效的JSON。像这样:
func (hash Hash) MarshalJSON() ([]byte, error) {
return []byte(`"` + hash.String() + `"`), nil
}
应该工作。
错误消息中的'v'
是base64编码文本中的第一个字符,因此该消息表明它在寻找有效的JSON类型(即字符串,数字,布尔值)时正在寻找'v'
,对象,数组或null),都不能以该字符开头。
进行此更改并在最后一行中调整类型:
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
)
type Hash [64]byte
func FromString(data string) (Hash, error) {
decoded, err := base64.StdEncoding.DecodeString(string(data))
if err != nil {
return Hash{}, err
}
hash := Hash{}
for index := 0; index < 64; index++ {
hash[index] = decoded[index]
}
return hash, nil
}
func (hash Hash) String() string {
return base64.StdEncoding.EncodeToString([]byte(hash[:64]))
}
func (hash Hash) MarshalJSON() ([]byte, error) {
return []byte(`"` + hash.String() + `"`), nil
}
func (hash *Hash) UnmarshalJSON(data []byte) error {
decoded, err := FromString(string(data[1 : len(data)-1]))
if err != nil {
return err
}
for index := 0; index < 64; index++ {
hash[index] = decoded[index]
}
return nil
}
func main() {
type TestStructure struct {
Hash Hash
Type string
}
object := TestStructure{
Hash: Hash{0xbd, 0xfe, 0xe0, 0xb1, 0x6c, 0xff, 0xb4, 0x51, 0x4c, 0x7b, 0xed, 0x33, 0xc1, 0x6d, 0xac, 0x5e, 0x80, 0x51, 0xec, 0xcb, 0x31, 0x21, 0x8c, 0x54, 0xb, 0xec, 0xbc, 0x7e, 0xbf, 0x4a, 0xce, 0x92, 0x3b, 0xcb, 0xf8, 0xdd, 0x82, 0x45, 0x34, 0xae, 0x58, 0x5, 0x3a, 0x7b, 0x18, 0xdd, 0x30, 0x5c, 0x7e, 0xed, 0xc9, 0xaa, 0x1e, 0x3a, 0x9a, 0x95, 0x30, 0xc3, 0x6b, 0xf8, 0xf9, 0x92, 0x43, 0xc6},
Type: "I'm a type",
}
data, err := json.Marshal(object)
fmt.Println(string(data), err)
}
产生预期的输出:
paul@mac:go64$ ./go64
{"Hash":"vf7gsWz/tFFMe+0zwW2sXoBR7MsxIYxUC+y8fr9KzpI7y/jdgkU0rlgFOnsY3TBcfu3Jqh46mpUww2v4+ZJDxg==","Type":"I'm a type"} <nil>
paul@mac:go64$
显然,在解组期间,您还需要处理引号。
答案 1 :(得分:0)
感谢@Peter发表的有关MarshalText / UnmarshalText的评论,我找到了一个不错的解决方案。可能有比for循环更好的方法来复制值,但是至少现在可以。
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
)
type Hash [64]byte
func FromString(data string) (Hash, error) {
decoded, err := base64.StdEncoding.DecodeString(string(data))
if err != nil {
return Hash{}, err
}
hash := Hash{}
for index := 0; index < 64; index++ {
hash[index] = decoded[index]
}
return hash, nil
}
func (hash Hash) String() string {
return base64.StdEncoding.EncodeToString([]byte(hash[:]))
}
func (hash Hash) MarshalText() (text []byte, err error) {
return []byte(hash.String()), nil
}
func (hash *Hash) UnmarshalText(text []byte) error {
decoded, err := base64.StdEncoding.DecodeString(string(text))
if err != nil {
return err
}
for index := 0; index < 64; index++ {
hash[index] = decoded[index]
}
return nil
}
func main() {
type TestStructure struct {
Hash Hash
Type string
}
object := TestStructure{
Hash: Hash{0xbd, 0xfe, 0xe0, 0xb1, 0x6c, 0xff, 0xb4, 0x51, 0x4c, 0x7b, 0xed, 0x33, 0xc1, 0x6d, 0xac, 0x5e, 0x80, 0x51, 0xec, 0xcb, 0x31, 0x21, 0x8c, 0x54, 0xb, 0xec, 0xbc, 0x7e, 0xbf, 0x4a, 0xce, 0x92, 0x3b, 0xcb, 0xf8, 0xdd, 0x82, 0x45, 0x34, 0xae, 0x58, 0x5, 0x3a, 0x7b, 0x18, 0xdd, 0x30, 0x5c, 0x7e, 0xed, 0xc9, 0xaa, 0x1e, 0x3a, 0x9a, 0x95, 0x30, 0xc3, 0x6b, 0xf8, 0xf9, 0x92, 0x43, 0xc6},
Type: "I'm a type",
}
data, err := json.Marshal(object)
fmt.Println(string(data), err)
ts := TestStructure{}
err = json.Unmarshal(data, &ts)
fmt.Printf("%+v\n", ts)
fmt.Println(err)
h, err := FromString(ts.Hash.String())
fmt.Printf("%+v\n", h)
fmt.Println(err)
}