json: 无法将对象解组为类型为 []*main.Config 的 Go 值。

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

json: cannot unmarshal object into Go value of type []*main.Config

问题

我是你的中文翻译助手,以下是你提供的代码的翻译:

  1. package main
  2. import (
  3. "errors"
  4. "github.com/gorilla/mux"
  5. "mime"
  6. "net/http"
  7. )
  8. type Config struct {
  9. Id string `json:"id"`
  10. entries map[string]string `json:"entries"`
  11. }
  12. type postServer struct {
  13. data map[string][]*Config
  14. }
  15. func (ts *postServer) createPostHandler(w http.ResponseWriter, req *http.Request) {
  16. contentType := req.Header.Get("Content-Type")
  17. mediatype, _, err := mime.ParseMediaType(contentType)
  18. if err != nil {
  19. http.Error(w, err.Error(), http.StatusBadRequest)
  20. return
  21. }
  22. if mediatype != "application/json" {
  23. err := errors.New("Expect application/json Content-Type")
  24. http.Error(w, err.Error(), http.StatusUnsupportedMediaType)
  25. return
  26. }
  27. rt, err := decodeBody(req.Body)
  28. if err != nil {
  29. http.Error(w, err.Error(), http.StatusBadRequest)
  30. return
  31. }
  32. id := createId()
  33. ts.data[id] = rt
  34. renderJSON(w, rt)
  35. }
  36. func (ts *postServer) getAllHandler(w http.ResponseWriter, req *http.Request) {
  37. allTasks := []*Config{}
  38. for _, v := range ts.data {
  39. allTasks = append(allTasks, v...)
  40. }
  41. renderJSON(w, allTasks)
  42. }
  43. func (ts *postServer) getPostHandler(w http.ResponseWriter, req *http.Request) {
  44. id := mux.Vars(req)["id"]
  45. task, ok := ts.data[id]
  46. if !ok {
  47. err := errors.New("key not found")
  48. http.Error(w, err.Error(), http.StatusNotFound)
  49. return
  50. }
  51. renderJSON(w, task)
  52. }
  53. func (ts *postServer) delPostHandler(w http.ResponseWriter, req *http.Request) {
  54. id := mux.Vars(req)["id"]
  55. if v, ok := ts.data[id]; ok {
  56. delete(ts.data, id)
  57. renderJSON(w, v)
  58. } else {
  59. err := errors.New("key not found")
  60. http.Error(w, err.Error(), http.StatusNotFound)
  61. }
  62. }
  63. func decodeBody(r io.Reader) ([]*Config, error) {
  64. dec := json.NewDecoder(r)
  65. dec.DisallowUnknownFields()
  66. var rt []*Config
  67. if err := dec.Decode(&rt); err != nil {
  68. return nil, err
  69. }
  70. return rt, nil
  71. }
  72. func renderJSON(w http.ResponseWriter, v interface{}) {
  73. js, err := json.Marshal(v)
  74. if err != nil {
  75. http.Error(w, err.Error(), http.StatusInternalServerError)
  76. return
  77. }
  78. w.Header().Set("Content-Type", "application/json")
  79. w.Write(js)
  80. }
  81. func createId() string {
  82. return uuid.New().String()
  83. }
  84. func main() {
  85. quit := make(chan os.Signal)
  86. signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
  87. router := mux.NewRouter()
  88. router.StrictSlash(true)
  89. server := postServer{
  90. data: map[string][]*Config{},
  91. }
  92. router.HandleFunc("/config/", server.createPostHandler).Methods("POST")
  93. router.HandleFunc("/configs/", server.getAllHandler).Methods("GET")
  94. router.HandleFunc("/config/{id}/", server.getPostHandler).Methods("GET")
  95. router.HandleFunc("/config/{id}/", server.delPostHandler).Methods("DELETE")
  96. // start server
  97. srv := &http.Server{Addr: "0.0.0.0:8000", Handler: router}
  98. go func() {
  99. log.Println("server starting")
  100. if err := srv.ListenAndServe(); err != nil {
  101. if err != http.ErrServerClosed {
  102. log.Fatal(err)
  103. }
  104. }
  105. }()
  106. <-quit
  107. log.Println("service shutting down ...")
  108. // gracefully stop server
  109. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  110. defer cancel()
  111. if err := srv.Shutdown(ctx); err != nil {
  112. log.Fatal(err)
  113. }
  114. log.Println("server stopped")
  115. }

你在Postman中发送的JSON数据是:

  1. {
  2. "entries": ["hello", "world"]
  3. }

你在decodeBody函数中遇到的错误是:

  1. json: cannot unmarshal object into Go value of type []*main.Config

你想知道问题出在哪里,可能是你发送了错误的JSON数据,或者在decodeBody函数中做错了什么。你在decodeBody函数中的var rt []*Config前面需要添加[],否则它将无法工作。

希望这可以帮助你解决问题!

英文:

I'm new to golang and json, we are using gorilla mux library and I'd like to do a post request in postman. In config struct entries needs to be a map like that and in post server I need to have an array of *Config in postServer struct. I have 3 go files.
Service.go file is this:

  1. package main
  2. import (
  3. &quot;errors&quot;
  4. &quot;github.com/gorilla/mux&quot;
  5. &quot;mime&quot;
  6. &quot;net/http&quot;
  7. )
  8. type Config struct {
  9. Id string `json:&quot;id&quot;`
  10. entries map[string]string `json:&quot;entries&quot;`
  11. }
  12. type postServer struct {
  13. data map[string][]*Config
  14. }
  15. func (ts *postServer) createPostHandler(w http.ResponseWriter, req *http.Request) {
  16. contentType := req.Header.Get(&quot;Content-Type&quot;)
  17. mediatype, _, err := mime.ParseMediaType(contentType)
  18. if err != nil {
  19. http.Error(w, err.Error(), http.StatusBadRequest)
  20. return
  21. }
  22. if mediatype != &quot;application/json&quot; {
  23. err := errors.New(&quot;Expect application/json Content-Type&quot;)
  24. http.Error(w, err.Error(), http.StatusUnsupportedMediaType)
  25. return
  26. }
  27. rt, err := decodeBody(req.Body)
  28. if err != nil {
  29. http.Error(w, err.Error(), http.StatusBadRequest)
  30. return
  31. }
  32. id := createId()
  33. ts.data[id] = rt
  34. renderJSON(w, rt)
  35. }
  36. func (ts *postServer) getAllHandler(w http.ResponseWriter, req *http.Request) {
  37. allTasks := []*Config{}
  38. for _, v := range ts.data {
  39. allTasks = append(allTasks, v...)
  40. }
  41. renderJSON(w, allTasks)
  42. }
  43. func (ts *postServer) getPostHandler(w http.ResponseWriter, req *http.Request) {
  44. id := mux.Vars(req)[&quot;id&quot;]
  45. task, ok := ts.data[id]
  46. if !ok {
  47. err := errors.New(&quot;key not found&quot;)
  48. http.Error(w, err.Error(), http.StatusNotFound)
  49. return
  50. }
  51. renderJSON(w, task)
  52. }
  53. func (ts *postServer) delPostHandler(w http.ResponseWriter, req *http.Request) {
  54. id := mux.Vars(req)[&quot;id&quot;]
  55. if v, ok := ts.data[id]; ok {
  56. delete(ts.data, id)
  57. renderJSON(w, v)
  58. } else {
  59. err := errors.New(&quot;key not found&quot;)
  60. http.Error(w, err.Error(), http.StatusNotFound)
  61. }
  62. }

I wanted to test createPostHandler.
Then I have helper.go file where I decoded json into go and rendered into json:

  1. package main
  2. import (
  3. &quot;encoding/json&quot;
  4. &quot;github.com/google/uuid&quot;
  5. &quot;io&quot;
  6. &quot;net/http&quot;
  7. )
  8. func decodeBody(r io.Reader) ([]*Config, error) {
  9. dec := json.NewDecoder(r)
  10. dec.DisallowUnknownFields()
  11. var rt []*Config
  12. if err := dec.Decode(&amp;rt); err != nil {
  13. return nil, err
  14. }
  15. return rt, nil
  16. }
  17. func renderJSON(w http.ResponseWriter, v interface{}) {
  18. js, err := json.Marshal(v)
  19. if err != nil {
  20. http.Error(w, err.Error(), http.StatusInternalServerError)
  21. return
  22. }
  23. w.Header().Set(&quot;Content-Type&quot;, &quot;application/json&quot;)
  24. w.Write(js)
  25. }
  26. func createId() string {
  27. return uuid.New().String()
  28. }

and the last one go file is main.go where I have this:

  1. package main
  2. import (
  3. &quot;context&quot;
  4. &quot;github.com/gorilla/mux&quot;
  5. &quot;log&quot;
  6. &quot;net/http&quot;
  7. &quot;os&quot;
  8. &quot;os/signal&quot;
  9. &quot;syscall&quot;
  10. &quot;time&quot;
  11. )
  12. func main() {
  13. quit := make(chan os.Signal)
  14. signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
  15. router := mux.NewRouter()
  16. router.StrictSlash(true)
  17. server := postServer{
  18. data: map[string][]*Config{},
  19. }
  20. router.HandleFunc(&quot;/config/&quot;, server.createPostHandler).Methods(&quot;POST&quot;)
  21. router.HandleFunc(&quot;/configs/&quot;, server.getAllHandler).Methods(&quot;GET&quot;)
  22. router.HandleFunc(&quot;/config/{id}/&quot;, server.getPostHandler).Methods(&quot;GET&quot;)
  23. router.HandleFunc(&quot;/config/{id}/&quot;, server.delPostHandler).Methods(&quot;DELETE&quot;)
  24. // start server
  25. srv := &amp;http.Server{Addr: &quot;0.0.0.0:8000&quot;, Handler: router}
  26. go func() {
  27. log.Println(&quot;server starting&quot;)
  28. if err := srv.ListenAndServe(); err != nil {
  29. if err != http.ErrServerClosed {
  30. log.Fatal(err)
  31. }
  32. }
  33. }()
  34. &lt;-quit
  35. log.Println(&quot;service shutting down ...&quot;)
  36. // gracefully stop server
  37. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  38. defer cancel()
  39. if err := srv.Shutdown(ctx); err != nil {
  40. log.Fatal(err)
  41. }
  42. log.Println(&quot;server stopped&quot;)
  43. }

And JSON whad I did send is this:

  1. {
  2. &quot;entries&quot;:[&quot;hello&quot;, &quot;world&quot;]
  3. }

And error what I'm getting in postman is this:

  1. json: cannot unmarshal object into Go value of type []*main.Config

I don't know what is a problem, maybe I'm sending wrong json or I just did something wrong in decodeBody, I needed to add [] in decodeBody in var rt []*Config because it wouldn't work otherwise.
Can someone help me to fix this please?

答案1

得分: 2

这是一个示例,展示了如何定义一个名为Config的结构体,你可以将样本JSON解析到其中。

编辑:字段entries已更改为map。

你可以在Playground上进行测试。

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. type Config struct {
  7. Id string `json:"id"`
  8. Entries map[string]string `json:"entries"`
  9. }
  10. func main() {
  11. str := `[{"id":"42", "entries":{"hello": "world"}}]`
  12. var tmp []Config
  13. err := json.Unmarshal([]byte(str), &tmp)
  14. if err != nil {
  15. fmt.Printf("error: %v", err)
  16. }
  17. var rt []*Config
  18. for _, c := range tmp {
  19. rt = append(rt, &c)
  20. }
  21. for _, c := range rt {
  22. for k, v := range c.Entries {
  23. fmt.Printf("id=%s key=%s value=%s\n", c.Id, k, v)
  24. }
  25. }
  26. }

希望对你有帮助!

英文:

This is an example of how you can define a struct Config that you can parse your sample JSON into.

EDIT: field entries changed to map.

You can play with it on Playground.

  1. package main
  2. import (
  3. &quot;encoding/json&quot;
  4. &quot;fmt&quot;
  5. )
  6. type Config struct {
  7. Id string `json:&quot;id&quot;`
  8. Entries map[string]string `json:&quot;entries&quot;`
  9. }
  10. func main() {
  11. str := `[{&quot;id&quot;:&quot;42&quot;, &quot;entries&quot;:{&quot;hello&quot;: &quot;world&quot;}}]`
  12. var tmp []Config
  13. err := json.Unmarshal([]byte(str), &amp;tmp)
  14. if err != nil {
  15. fmt.Printf(&quot;error: %v&quot;, err)
  16. }
  17. var rt []*Config
  18. for _, c := range tmp {
  19. rt = append(rt, &amp;c)
  20. }
  21. for _, c := range rt {
  22. for k, v := range c.Entries {
  23. fmt.Printf(&quot;id=%s key=%s value=%s\n&quot;, c.Id, k, v)
  24. }
  25. }
  26. }

huangapple
  • 本文由 发表于 2022年4月30日 21:14:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/72068828.html
匿名

发表评论

匿名网友

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

确定