英文:
Go JSON Marshaller errors when converting int64 bytes
问题
我正在编写一个时间别名,将一些时间转换为Unix格式的JSON Marshal(在其中留下了一些我实验性的测试代码)。
type NotifyTime time.Time
// MarshalJSON 实现了 marshaller 接口。将 time.Time 转换为字节中的 Unix 时间
func (t NotifyTime) MarshalJSON() ([]byte, error) {
// unixTime := time.Time(t).Unix()
unixTime := 1626132059 // unixTime := time.Now().Unix()
buffer := make([]byte, 8)
binary.PutVarint(buffer, int64(unixTime))
// binary.LittleEndian.PutUint64(buffer, uint64(unixTime))
// 尝试转换回来
fmt.Println(string(buffer))
unixIntValue := int64(binary.LittleEndian.Uint64(buffer))
fmt.Println(unixIntValue)
return buffer, nil
}
当我对一个包含 NotifyTime 结构的对象运行 json.Marshal 时,它报错,错误信息如下:
json: error calling MarshalJSON for type notify.NotifyTime: invalid character '¶' looking for beginning of value
以下是相关的代码片段:
type TestMe struct {
Time NotifyTime `json:"time"`
}
testJSON := TestMe{
Time: NotifyTime(time.Now()),
}
marshalled, err := json.Marshal(testJSON)
我已经改为将其转换为字符串进行编组,但仍然对此情况感到好奇。当我逐步执行代码时,似乎是因为在 go/1.16.2/libexec/src/encoding/json/indent.go 的 compact 函数中,它在循环遍历 JSON 的编组字节时,第一个(第0个)字节未通过 go/1.16.2/libexec/src/encoding/json/scanner.go 的检查。
英文:
I am writing a time alias to JSON Marshal some time into a Unix format (left some of my experimenting test code in there
type NotifyTime time.Time
// MarshalJSON implements marshaller interface. Marshals time.Time into unix time in bytes
func (t NotifyTime) MarshalJSON() ([]byte, error) {
// unixTime := time.Time(t).Unix()
unixTime := 1626132059 // unixTime := time.Now().Unix()
buffer := make([]byte, 8)
binary.PutVarint(buffer, int64(unixTime))
// binary.LittleEndian.PutUint64(buffer, uint64(unixTime))
// try to convert back
fmt.Println(string(buffer))
unixIntValue := int64(binary.LittleEndian.Uint64(buffer))
fmt.Println(unixIntValue)
return buffer, nil
}
When I run json.Marshal on an object with NotifyTime struct, it errs, with the following,
json: error calling MarshalJSON for type notify.NotifyTime: invalid character '¶' looking for beginning of value
type TestMe struct {
Time NotifyTime `json:"time"`
}
testJSON := TestMe{
Time: NotifyTime(time.Now()),
}
marshalled, err := json.Marshal(testJSON)
I have switched to marshalling it as a string, but still curious as to why this happens. When stepping through the code it seems to be because
on function compact on go/1.16.2/libexec/src/encoding/json/indent.go:17
it is looping over the marshalled bytes of the JSON
and the first (0th) byte fails the checks in
go/1.16.2/libexec/src/encoding/json/scanner.go:247
答案1
得分: 2
让我们暂时不考虑编码time.Time
的方面,而是专注于将int64
转换为JSON的方式。
binary.PutVarint
使用适用于低级别的网络或文件格式的编码。对于常量1626132059,它会将其写入缓冲区[182 185 230 142 12 0 0 0]
。第一个字符是UTF-8中的182 PILCROW SIGN
。这就是为什么你会得到一个错误,类似于:
json: error calling MarshalJSON for type main.NotifyTime: invalid character '¶' looking for beginning of value
这不是一个有效的JSON值的开头。你需要找到一个int64的编码,它是一个JSON值,比如一个十进制数1626132059
或一个十六进制数字的字符串"60ecce5b"
。
一般来说,当将二进制字符串值放入JSON时,你需要小心,因为它们可能包含需要转义的特殊字符。
英文:
Let's put aside the aspect of encoding a time.Time
and lets focus on how the int64
is being turned into JSON.
binary.PutVarint
uses an encoding that is appropriate for low level wire or file formats. For the constant 1626132059, this writes into buffer [182 185 230 142 12 0 0 0]
. The first character is 182 PILCROW SIGN
in UTF-8. This is where '¶' comes from. You are getting an error like:
json: error calling MarshalJSON for type main.NotifyTime: invalid character '¶' looking for beginning of value
This is not the beginning of a valid JSON value. You will need to find an encoding of int64 that is a JSON value, such as a decimal number 1626132059
or a string of hexadecimal digits "60ecce5b"
.
In general you need to be careful putting binary string values into JSON as these can contain special characters that need to be escaped.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论