Go踩坑,JSON序列化规则

140 阅读1分钟

场景还原

假如有如下的接口,它会返回一些数据,我们通过一个Response结构体把响应做一个封装

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

type Response struct {
	code int
	data any
	msg  string
}

func main() {
	r := gin.Default()

	r.GET("/data", func(c *gin.Context) {
		response := Response{
			code: http.StatusOK,
			data: "some data",
			msg:  http.StatusText(http.StatusOK),
		}

		c.JSON(http.StatusOK, response)
	})

	r.Run(":8080")
}

运行后访问接口,期望的响应是

{
    "Code":200,
    "Data":"some data",
    "Msg":"OK",
}

而实际得到的响应是 image.png 显然和我们的预期不符,下面开始排查问题

排查

gin框架在调用c.JSON时,对于我们传进去的data数据,实际上是调用json.Marshal进行处理的

// WriteJSON marshals the given interface object and writes it with custom ContentType.
func WriteJSON(w http.ResponseWriter, obj any) error {
	writeContentType(w, jsonContentType)
	jsonBytes, err := json.Marshal(obj)
	if err != nil {
		return err
	}
	_, err = w.Write(jsonBytes)
	return err
}

json.Marshal有一个规则,就是如果解析的对象是一个结构体,那么只有导出字段,也就是首字母大写的字段会被解析

问题迎刃而解,我们的Response里字段都是包级别的,不可导出,也就不会被解析出来,自然在响应里看不到

结语

这个问题比较隐蔽,主要还是对于封装函数的用法不了解,踩过的坑记住,后面不踩了

Author: KreanXie