在Go中解码来自POST请求的JSON失败

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

Decoding JSON from POST request fails in Go

问题

我用以下的JSON数据向我的Go应用程序发送了一个POST请求:

var test = {text: "Lorem ipsum dolor sit amet"};

$.ajax({
  url: "/api/test/add",
  type: "POST",
  dataType: "json",
  contentType: "application/json; charset=utf-8",
  data: JSON.stringify(test),
  success: function(data) {
    // ...
  },
  error: function(xhr, status, err) {
    // ...
  }
});

在我的Go应用程序中,我有以下的代码(使用vestigo):

type Test struct {
  id   int
  text string
}

func apiAddTestHandler(w http.ResponseWriter, r *http.Request) {
  r_body, err := ioutil.ReadAll(r.Body)
  if err != nil {
	panic(err)
  }

  // 如果我尝试将r_body转换为字符串(string(r_body)),我会得到{"text": "Lorem ipsum dolor sit amet"},看起来一切都正常。

  var test Test
  err = json.Unmarshal(r_body, &test)
  if err != nil {
	panic(err)
  }
  
  // 在下面处理test结构体时,我得到{id:0 text:},如果我尝试使用或打印test的值(fmt.Printf("%+v\n", test))。

}

func main() {
  router := vestigo.NewRouter()
  router.Post("/api/test/add", apiAddTestHandler)

  err := http.ListenAndServe(":3000", router)
  if err != nil {
	log.Fatal("ListenAndServe: ", err)
  }
}

问题是,在apiAddTestHandler()函数中,我无法将解码后的JSON数据填充到test结构体中。在注释中有更多的信息。我还尝试了下面的代码片段,但没有成功:

decoder := json.NewDecoder(r.Body)
var test Test
err := decoder.Decode(&test)
if err != nil {
  panic(err)
}

问题出在哪里?

英文:

I send a POST request to my Go application with JSON data like below:

var test = {text: "Lorem ipsum dolor sit amet"};

$.ajax({
  url: "/api/test/add",
  type: "POST",
  dataType: "json",
  contentType: "application/json; charset=utf-8",
  data: JSON.stringify(test),
  success: function(data) {
    // ...
  },
  error: function(xhr, status, err) {
    // ...
  }
});

In my Go application I have the following code (using vestigo):

type Test struct {
  id   int
  text string
}

func apiAddTestHandler(w http.ResponseWriter, r *http.Request) {
  r_body, err := ioutil.ReadAll(r.Body)
  if err != nil {
	panic(err)
  }

  // Here looks like everything is ok because I get
  // {"text": "Lorem ipsum dolor sit amet"} if I try
  // to convert r_body to string (string(r_body)).

  var test Test
  err = json.Unmarshal(r_body, &test)
  if err != nil {
	panic(err)
  }
  
  // Process test struct below, but here I get
  // {id:0 text:} if I try to use or print the value
  // of test (fmt.Printf("%+v\n", test)).
}

func main() {
  router := vestigo.NewRouter()
  router.Post("/api/test/add", apiAddTestHandler)

  err := http.ListenAndServe(":3000", router)
  if err != nil {
	log.Fatal("ListenAndServe: ", err)
  }
}

The problem is, that in apiAddTestHandler() I cannot "populate" the test struct with the decoded JSON data. A little bit more info in the comments. I also tried the below snippet with no luck:

decoder := json.NewDecoder(r.Body)
var test Test
err := decoder.Decode(&test)
if err != nil {
  panic(err)
}

What is the problem?

答案1

得分: 3

Unmarshal文档中(强调是我的):

> 为了将JSON解组为结构体,Unmarshal将传入的对象键与Marshal使用的键进行匹配(可以是结构字段名称或其标签),优先选择精确匹配,但也接受不区分大小写的匹配。Unmarshal只会设置结构体的导出字段

您需要更改结构体中的字段定义:

type Test struct {
  ID   int
  Text string
}

请注意,根据Golang命名约定,我使用了ID而不是Id

英文:

From the Unmarshal documentation (emphasis is mine):

> To unmarshal JSON into a struct, Unmarshal matches incoming object keys to the keys used by Marshal (either the struct field name or its tag), preferring an exact match but also accepting a case-insensitive match. Unmarshal will only set exported fields of the struct.

You need to change the field definition in your struct:

type Test struct {
  ID   int
  Text string
}

Note I used ID instead of Id per Golang naming conventions.

huangapple
  • 本文由 发表于 2016年3月13日 19:48:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/35969856.html
匿名

发表评论

匿名网友

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

确定