Go如何处理JSON接口数据_HTTP JSON通信流程

9次阅读

go中用http.Client发起jsON请求需手动序列化、设Content-Type头、检查状态码;解析响应时应先读取完整body,用指针json.RawMessage处理NULL和嵌套字段;须复用带超时和连接池配置的全局client。

Go如何处理JSON接口数据_HTTP JSON通信流程

Go中用http.Client发起JSON请求的典型写法

Go标准库不自动处理JSON序列化/反序列化,必须手动编码请求体、设置Content-Type头,并检查响应状态码。直接用http.Post容易忽略错误分支和超时控制。

  • 始终用&http.Client{Timeout: 10 * time.Second}显式设超时,避免协程永久阻塞
  • 请求体必须是[]byte,用json.Marshal生成,不能传结构体指针直接给bytes.NewReader
  • 务必检查resp.StatusCode是否为2xxhttp.Post只判断网络层错误,不校验HTTP状态码
  • Content-Type头必须设为"application/json; charset=utf-8",部分API(如gitHub)严格校验该字段
client := &http.Client{Timeout: 10 * time.Second} data := map[String]string{"name": "alice", "age": "30"} body, _ := json.Marshal(data) req, _ := http.NewRequest("POST", "https://api.example.com/users", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json; charset=utf-8") resp, err := client.Do(req) if err != nil {     log.Fatal(err) } if resp.StatusCode < 200 || resp.StatusCode >= 300 {     log.Fatalf("HTTP %d", resp.StatusCode) }

json.Unmarshal解析响应时的常见panic

直接对resp.Body调用json.Unmarshal会panic:如果响应不是合法JSON,或结构体字段标签与JSON key不匹配,或遇到null值但目标字段是非nil类型(如string而非*string)。

  • 先用ioutil.ReadAll(Go 1.16+ 改用io.ReadAll)读取完整body,避免后续多次读取空内容
  • 检查err是否为json.SyntaxError,可定位到具体出错位置
  • 对可能为null的字段,用指针类型*string)或sql.NullString类包装,避免解码失败
  • json.RawMessage延迟解析嵌套JSON字段,防止结构体定义不全导致崩溃
body, _ := io.ReadAll(resp.Body) var result struct {     ID     int      `json:"id"`     Name   *string  `json:"name"` // 允许null     Extra  json.RawMessage `json:"extra,omitempty"` } if err := json.Unmarshal(body, &result); err != nil {     if syntaxErr, ok := err.(*json.SyntaxError); ok {         log.Printf("JSON syntax error at offset %d", syntaxErr.Offset)     }     log.Fatal(err) }

如何安全复用http.Client并管理连接池

每次新建http.Client会导致TCP连接无法复用,短连接频繁创建销毁,触发too many open files错误。默认http.DefaultClient虽可复用,但无超时控制,生产环境禁用。

  • 全局复用一个*http.Client实例,不要按请求新建
  • 通过Transport配置连接池:MaxIdleConnsMaxIdleConnsPerHost设为100起,避免连接耗尽
  • IdleConnTimeout30 * time.Second,防止TIME_WaiT
  • 若需带认证(如Bearer Token),用context.WithValue传token,而非在Client上硬编码Header
var httpClient = &http.Client{     Timeout: 10 * time.Second,     Transport: &http.Transport{         MaxIdleConns:        100,         MaxIdleConnsPerHost: 100,         IdleConnTimeout:     30 * time.Second,     }, }

接口返回非标准JSON(如带bomhtml错误页)怎么办

很多HTTP API在出错时不返回JSON,而是返回HTML错误页或纯文本,直接json.Unmarshal会报invalid character '。不能依赖Content-Type头,必须先检查响应内容。

  • 读取body后,用bytes.HasPrefix(body, []byte{'{','[','"'})粗略判断是否为JSON
  • 若不是JSON且resp.StatusCode >= 400,应把body当错误信息处理,而不是强转结构体
  • 对含UTF-8 BOM的响应(xEFxBBxBF),用bytes.TrimPrefix(body, []byte{0xEF, 0xBB, 0xBF})清理
  • 避免用strings.Contains(string(body), "error")判断错误,易误判正常JSON中的字段名

真正麻烦的是那些文档写JSON、实际返回混合格式的第三方API——得靠日志记录原始body才能定位问题。

text=ZqhQzanResources