如何正确解析 JSON 数组中的多个 JSON 对象

3次阅读

如何正确解析 JSON 数组中的多个 JSON 对象

本文详解 go 语言中解析嵌套 json 数组(如 `{“Array”: […]}`)的完整流程,涵盖结构体字段映射、json 标签修正、反序列化及遍历操作,并提供可运行示例与关键注意事项。

go 中解析形如 {“array”: […]} 的 jsON 响应时,常见错误源于结构体字段名与 json 键名不匹配、JSON 标签(json:)书写错误,或顶层结构体未正确对应嵌套层级。以你提供的数据为例,原始 JSON 的顶层键是 “array”,而非 “createUserArray”;且每个对象中字段如 “entity_title” 应映射为 Go 字段 EntityTitle(而非 EntityTitleName),同时注意拼写一致性(如 “posibble_user_email” 中的 posibble 是故意拼错,需原样保留标签)。

以下是修正后的完整实践方案:

✅ 正确的结构体定义

type MsgCreateUserArray struct {     CreateUser []MsgCreateUserJson `json:"array"` // 关键:匹配 JSON 中的 "array" 键 }  type MsgCreateUserJson struct {     EntityTitle       String `json:"entity_title"`        // 原字段名,非 entity_title_name     EntityOrgName     string `json:"entity_org_name"`     PossibleUserName  string `json:"possible_user_name"`     PosibbleUserEmail string `json:"posibble_user_email"` // 注意:JSON 中拼写为 posibble(非 possible)     UserPositionTitle string `json:"user_position_title"`     MsgBodyID         int64  `json:"msg_body_id,omitempty"` // 使用 int64 更符合 ID 语义;omitempty 允许缺失 }

⚠️ 注意事项:json:”…” 标签必须严格匹配原始 JSON 的 key 名称(包括大小写和拼写),例如 “posibble_user_email” 不可写作 “possible_user_email”;MsgBodyID 推荐使用 int64 而非 string,避免后续数值运算需转换;omitempty 仅在字段值为空(零值)时忽略序列化,对反序列化无影响,但能提升健壮性。

✅ 解析与遍历逻辑

func parseJson(rw http.ResponseWriter, request *http.Request) {     defer request.Body.Close() // 防止资源泄漏!务必关闭 Body      decoder := json.NewDecoder(request.Body)     var payload MsgCreateUserArray      if err := decoder.Decode(&payload); err != nil {         http.Error(rw, "Invalid JSON: "+err.Error(), http.StatusbadRequest)         return     }      // 安全遍历数组 —— 即使为空也不会 panic     for i, user := range payload.CreateUser {         log.Printf("Item %d: %s at %s, position: %s, ID: %d",              i+1,             user.PossibleUserName,             user.EntityTitle,             user.UserPositionTitle,             user.MsgBodyID,         )         // ✅ 此处可对每个 MsgCreateUserJson 对象执行业务逻辑:         // 如存入数据库、触发通知、校验邮箱 html 内容等     }      rw.WriteHeader(http.StatusOK)     rw.Write([]byte("Parsed successfully")) }

✅ 完整可运行示例(含测试用 HTTP 请求)

package main  import (     "encoding/json"     "log"     "net/http" )  // ...(上述结构体定义)  func parseJson(rw http.ResponseWriter, request *http.Request) {     defer request.Body.Close()     decoder := json.NewDecoder(request.Body)     var payload MsgCreateUserArray      if err := decoder.Decode(&payload); err != nil {         http.Error(rw, "JSON decode error: "+err.Error(), http.StatusBadRequest)         return     }      log.Printf("Received %d user entries", len(payload.CreateUser))     for _, u := range payload.CreateUser {         log.Printf("- %s (%s), %s → ID=%d",              u.PossibleUserName, u.UserPositionTitle, u.EntityTitle, u.MsgBodyID)     }      rw.WriteHeader(http.StatusOK) }  func main() {     http.HandleFunc("/parse", parseJson)     log.Println("Server starting on :1337...")     log.Fatal(http.ListenAndServe(":1337", nil)) }

? 测试方式(终端命令)

curl -X POST http://localhost:1337/parse    -H "Content-Type: application/json"    -d '{     "array": [       {         "entity_title":"University of Phoenix",         "entity_org_name":"CS Club",         "possible_user_name":"Johnny Ive",         "posibble_user_email":"johnny@example.com",         "user_position_title":"President",         "msg_body_id":4       }     ]   }'

✅ 总结

  • 结构体字段名无关紧要,json 标签才是反序列化的唯一依据
  • 始终检查 JSON 原始结构(推荐用 jq 或在线 formatter 校验);
  • 使用 defer req.Body.Close() 防止连接泄漏;
  • 遍历时优先用 range 获取值副本(除非需修改原切片);
  • 对于含 HTML 片段的字段(如邮箱链接),后续处理时应做 xss 过滤或安全解码。

掌握这一模式后,你可轻松扩展支持任意深度嵌套的 JSON 数组解析场景。

text=ZqhQzanResources