Json Decode无法将JSON中的时间戳解析为Go结构体。

huangapple go评论79阅读模式
英文:

Json Decode cannot parse timestamp in json into Go struct

问题

我正在尝试获取一个HTTP请求体,它是一个JSON对象,并将其解码为我定义的Go结构体。

结构体中有两个字段的类型是time.Time。当只有一个这样类型的字段时,一切正常。

但是,如果在Go结构体中有多个time.Time类型的字段,我无法解码它,并得到以下错误:

2014/11/01 01:07:04 parsing time "null" as ""2006-01-02T15:04:05Z07:00"": cannot parse "null" as """"

问题出在解码的代码行上。尽管我进行了调试,但没有得到有意义的结果。这个问题看起来很奇怪,实际上不应该出现。

我在这里漏掉了什么?

func register(w http.ResponseWriter, r *http.Request){
	//读取请求体JSON并转换为Go类型

    var requestBody = []byte(`{"username":"qwewwwqweqwe","password":"can","usertype":"student","firstname":"","midname":null,"surname":null,"signuptimestamp":null,"userstatus":null,"phone":null,"email":null,"address":null,"city":null,"country":null,"language":null,"lastlogintimestamp":null}`)
			
	type RegisterStructure struct {
		Id int `json:"id"`
		Timestamp time.Time `json:"timestamp,omitempty"`
		SignupTimestamp time.Time `json:"signuptimestamp,omitempty"`
	    Username string `json:"username"`
		Password string `json:"password"`
		UserType string `json:"usertype"`
		FirstName string `json:"firstname"`
		Midname string `json:"midname"`
		Surname string `json:"surname"`
		UserStatus string `json:"userstatus"`
		Phone string `json:"phone"`
		Email string `json:"email"`
		Address string `json:"address"`
		City string `json:"city"`
		Country string `json:"country"`
		Language string `json:"language"`
		//LastLoginTimestamp time.Time `json:"lastlogintimestamp,omitempty"`
	}
	var registerInstance RegisterStructure
	var now = time.Now()
	fmt.Printf("现在是 %v", now)
	fmt.Println()
	fmt.Printf("1 在这里初始化后的 registerInstance 是 %v", registerInstance)
	fmt.Println()
	
	registerInstance = RegisterStructure{Timestamp: now, SignupTimestamp: now}
	fmt.Printf("在这里将其设置为变量 now 后的 registerInstance 是 %v", registerInstance)
	fmt.Println()
	
	dec := json.NewDecoder(bytes.NewReader(requestBody))
	err = dec.Decode(&registerInstance)
	if err != nil {
		fmt.Printf("这里发生了错误。")
		log.Fatal(err)
	}
}
英文:

I am trying to obtain an HTTP request body which is a json object and decode it into a Go struct I have defined.

Two of the fields of the struct is of time.Time type. While having only one such typed field everything works correctly.

If I have more than one time.Time typed fields in the go struct I cannot decode it and get the error:

2014/11/01 01:07:04 parsing time "null" as ""2006-01-02T15:04:05Z07:00"": cannot parse "null" as """

The problem is in the decoding lines. Despite my debugging efforts I could have reached a meaningful result. That issue seems strange which is actually should not be.

What am I missing here?

func register(w http.ResponseWriter, r *http.Request){
//Read Request Body JSON Into Go Types
var requestBody = []byte(`{"username":"qwewwwqweqwe","password":"can","usertype":"student","firstname":"",‌​"midname":null,"surname":null,"signuptimestamp":null,"userstatus":null,"phone":nu‌​ll,"email":null,"address":null,"city":null,"country":null,"language":null,"lastlo‌​gintimestamp":null}`)
type RegisterStructure struct {
Id int `json:"id"`
Timestamp time.Time `json:"timestamp,omitemty"`
SignupTimestamp time.Time `json:"signuptimestamp,omitempty"`
Username string `json:"username"`
Password string `json:"password"`
UserType string `json:"usertype"`
FirstName string `json:"firstname"`
Midname string `json:"midname"`
Surname string `json:"surname"`
UserStatus string `json:"userstatus"`
Phone string `json:"phone"`
Email string `json:"email"`
Address string `json:"address"`
City string `json:"city"`
Country string `json:"country"`
Language string `json:"language"`
//LastLoginTimestamp time.Time `json:"lastlogintimestamp,omitempty"`
}
var registerInstance RegisterStructure
var now = time.Now()
fmt.Printf("now is %v", now)
fmt.Println()
fmt.Printf("1 registerInstance after inited here is %v", registerInstance)
fmt.Println()
registerInstance = RegisterStructure{Timestamp: now, SignupTimestamp: now,}
fmt.Printf("registerInstance after set to var now here is %v", registerInstance)
fmt.Println()
dec := json.NewDecoder(bytes.NewReader(requestBody))
err = dec.Decode(&registerInstance)
if err != nil {
fmt.Printf("error happens here.")
log.Fatal(err)
}

答案1

得分: 7

好的,下面是翻译好的内容:

好的。这是一个可复现的示例,演示了你所看到的错误。

package main

import (
	"encoding/json"
	"fmt"
	"bytes"
	"time"
)

type RegisterStructure struct {
	SignupTimestamp time.Time `json:"signuptimestamp,omitempty"`
}

func main() {
	requestBody := []byte(`{"signuptimestamp" : null}`)
	dec := json.NewDecoder(bytes.NewReader(requestBody))
	registerInstance := RegisterStructure{}
	err := dec.Decode(&registerInstance)
	if err != nil {
		fmt.Println(err)
	}
}

你所看到的错误与有多个时间戳无关。这就是为什么在调试这种情况时,展示输入是至关重要的,你应该返回并更改你的问题,将一个示例的requestBody作为问题内容的一部分。否则,很难猜测你在做什么。

问题出在null值没有被time.Time的JSON解码器处理。time.Time文档中写道:UnmarshalJSON实现了json.Unmarshaler接口。时间应该是一个以RFC 3339格式引用的字符串。

null不是这样的值:在这种情况下,解码器不会尝试为时间戳构造一个“零”值。

你需要做的是将SignupTimestamp的类型从time.Time更改为*time.Time,这样null值可以明确地表示为nil指针。

这里有一个示例来演示:

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"time"
)

type RegisterStructure struct {
	SignupTimestamp *time.Time `json:"signuptimestamp,omitempty"`
}

func main() {
	requestBodies := []string{
		`{"signuptimestamp" : "1985-04-12T23:20:50.52Z"}`,
		`{"signuptimestamp" : null}`,
	}
	for _, requestBody := range requestBodies {
		dec := json.NewDecoder(bytes.NewReader([]byte(requestBody)))
		registerInstance := RegisterStructure{}
		err := dec.Decode(&registerInstance)
		if err != nil {
			fmt.Println(err)
		}
		fmt.Printf("%#v\n", registerInstance)
	}
}
英文:

Ok. Here is a reproducible example that demonstrates the error you're seeing.

package main
import (
"encoding/json"
"fmt"
"bytes"
"time"
)
type RegisterStructure struct {
SignupTimestamp time.Time `json:"signuptimestamp,omitempty"`
}
func main() {
requestBody := []byte(`{"signuptimestamp" : null}`)
dec := json.NewDecoder(bytes.NewReader(requestBody))
registerInstance := RegisterStructure{}
err := dec.Decode(&registerInstance)
if err != nil {
fmt.Println(err)
}
}

The error you're seeing has nothing to do with having multiple timestamps. This is why showing inputs is critical for debugging situations like this, and why you should go back and change your question to include a sample requestBody as part of the question content. Otherwise, it becomes very difficult to guess what you're doing.

What's happening is that null is not handled by the JSON unmarshaller for time.Time. The documentation for time.Time's unmarshaller says: UnmarshalJSON implements the json.Unmarshaler interface. The time is expected to be a quoted string in RFC 3339 format.

null is not such a value: the decoder in this case will not try to construct a "zero" value for the timestamp.

What you want to do is change the type of SignupTimestamp from time.Time to *time.Time, so that the null value can be explicitly represented as a nil pointer.

Here is an example to demonstrate:

package main
import (
"bytes"
"encoding/json"
"fmt"
"time"
)
type RegisterStructure struct {
SignupTimestamp *time.Time `json:"signuptimestamp,omitempty"`
}
func main() {
requestBodies := []string{
`{"signuptimestamp" : "1985-04-12T23:20:50.52Z"}`,
`{"signuptimestamp" : null}`,
}
for _, requestBody := range requestBodies {
dec := json.NewDecoder(bytes.NewReader([]byte(requestBody)))
registerInstance := RegisterStructure{}
err := dec.Decode(&registerInstance)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%#v\n", registerInstance)
}
}

huangapple
  • 本文由 发表于 2014年11月1日 07:16:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/26684752.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定