json.Marshal自定义类型为base64字符串

问题描述 投票:0回答:2

我有一个自定义类型(散列[64]字节)和我试图实现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

我究竟做错了什么?

json go encoding types marshalling
2个回答
2
投票

MarshalJSON方法需要包括在它返回的值包封的引号,否则你最终无效JSON。就像是:

func (hash Hash) MarshalJSON() ([]byte, error) {
    return []byte(`"` + hash.String() + `"`), nil
}

应该管用。

在您的错误信息'v'是您的Base64编码的文本的第一个字符,因此消息显示它的发现'v'当它在寻找一个有效的JSON类型(即字符串,数字,布尔值,对象,数组或空),没有它可以与字符开头。

制作这种变化和调整线下决赛的类型:

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$ 

很明显,你还需要解组期间处理引号了。


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)
}
© www.soinside.com 2019 - 2024. All rights reserved.