Golang中gin框架绑定解析json数据的两种方法

 更新时间:2023年12月25日 10:14:53   作者:李迟  
本文介绍 Golang 的 gin 框架接收json数据并解析的2种方法,文中通过代码示例介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下

本文介绍 Golang 的 gin 框架接收json数据并解析的2种方法。

起因及排查

某微服务工程,最近测试发现请求超时,由于特殊原因超时较短,如果请求处理耗时超过1秒则认为失败。排查发现,可能是gin接收解析json数据存在耗时,代码使用ctx.ShouldBindJSON直接解析得到所需结构体,然后通过自实现的FormatJsonStruct函数格式化并输出到日志。该格式函数如下:

func FormatJsonStruct(str interface{}, format bool) (ret string) {
	ret = ""
	jsonstr, err := json.Marshal(str)
	if err != nil {
		return
	}
	if format {
		var out bytes.Buffer
		_ = json.Indent(&out, []byte(jsonstr), "", "    ")
		ret = out.String()
	} else {
		ret = string(jsonstr)
	}

	return
}

从上述过程看到,先是调用了ShouldBindJSON,再调用了Marshal函数解析成字符串。于是考虑调用ReadAll读取数据,再用Unmarshal解析成结构体,直接输出结构体数据。下面模拟2种不同的解析josn方法。

模拟程序

本节结合代码,简单描述模拟程序。详见文附录。

一般地,在gin中,业务处理函数带有*gin.Context参数,如本文的HandleGinShouldBindJSON,使用ctx.ShouldBindJSON(&request)将ctx中带的数据直接转换成目标结构体。

也可以通过ioutil.ReadAll(ctx.Request.Body)先读取客户端来的数据,由于约定为json格式数据,所以可以用json.Unmarshal解析成结构体。

无法哪种方法,其实都很方便,相对而言,前者更便捷。

测试结果

使用curl模拟请求命令,示例如下:

curl http://127.0.0.1:9000/foo -X POST -H "Content-Type:application/json" -d  '{"id":"test_001", "op":"etc", "timestamp":12342134341234, "data":{"name":"foo", "addr":"bar", "code":450481, "age":100}}'

curl http://127.0.0.1:9000/bar -X POST -H "Content-Type:application/json" -d  '{"id":"test_001", "op":"etc", "timestamp":12342134341234, "data":{"name":"foo", "addr":"bar", "code":450481, "age":100}}'

服务端输出日志:

=== RUN   TestGin
test of gin
run gin
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.        
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] POST   /foo                      --> webdemo/test/gin_test.HandleGinShouldBindJSON (1 handlers)
[GIN-debug] POST   /bar                      --> webdemo/test/gin_test.HandleGinUnmarshal (1 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on :9000
ShouldBindJSON: request: #{test_001 etc 12342134341234 {foo bar 450481 100}}
Unmarshal request: #{test_001 etc 12342134341234 {foo bar 450481 100}}
exit status 0xc000013a

小结

就目前测试和修改结果看,本文所述方法并非主因,真正原因待查。

附完整代码

/*
结构体
{
    "id": "test_001",
    "op": "etc",
    "timestamp": 12342134341234,
    "data": {
        "name": "foo",
        "addr": "bar",
        "code": 450481,
        "age": 100
    }
}

curl http://127.0.0.1:9000/foo -X POST -H "Content-Type:application/json" -d  '{"id":"test_001", "op":"etc", "timestamp":12342134341234, "data":{"name":"foo", "addr":"bar", "code":450481, "age":100}}'

curl http://127.0.0.1:9000/bar -X POST -H "Content-Type:application/json" -d  '{"id":"test_001", "op":"etc", "timestamp":12342134341234, "data":{"name":"foo", "addr":"bar", "code":450481, "age":100}}'

*/

package test

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"strings"
	"testing"

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

var g_port string = "9000"

type MyRequest_t struct {
	Id        string    `json:"id"`
	Op        string    `json:"op"`
	Timestamp int       `json:"timestamp"`
	Data      ReqData_t `json:"data"`
}

type ReqData_t struct {
	Name string `json:"name"`
	Addr string `json:"addr"`
	Code int    `json:"code"`
	Age  int    `json:"age"`
}

func routerPost(r *gin.Engine) {
	r.POST("/foo", HandleGinShouldBindJSON)
	r.POST("/bar", HandleGinUnmarshal)
}

func initGin() {
	fmt.Println("run gin")
	router := gin.New()
	routerPost(router)

	router.Run(":" + g_port)
}

func HandleGinShouldBindJSON(ctx *gin.Context) {
	var request MyRequest_t
	var err error
	ctxType := ctx.Request.Header.Get("Content-Type")
	if strings.Contains(ctxType, "application/json") { // 纯 json
		// 先获取总的json
		if err = ctx.ShouldBindJSON(&request); err != nil {
			fmt.Printf("ShouldBindJSON failed: %v\n", err)
			return
		}

		fmt.Printf("ShouldBindJSON: request: #%v\n", request)
	} else {
		fmt.Println("非json")
		return
	}
}

func HandleGinUnmarshal(ctx *gin.Context) {
	var request MyRequest_t
	var err error
	var reqbuffer []byte
	ctxType := ctx.Request.Header.Get("Content-Type")
	if strings.Contains(ctxType, "application/json") { // 纯 json

		reqbuffer, err = ioutil.ReadAll(ctx.Request.Body)
		if err != nil {
			fmt.Printf("ReadAll body failed: %v\n", err)
			return
		}
		err = json.Unmarshal(reqbuffer, &request)
		if err != nil {
			fmt.Printf("Unmarshal to request failed: %v\n", err)
			return
		}
		fmt.Printf("Unmarshal request: #%v\n", request)
	} else {
		fmt.Println("非json")
		return
	}
}

func TestGin(t *testing.T) {
	fmt.Println("test of gin")

	initGin()
}

以上就是Golang中gin框架绑定解析json数据的两种方法的详细内容,更多关于Golang gin绑定解析json的资料请关注脚本之家其它相关文章!

相关文章

  • GO语言的map类型实例详解

    GO语言的map类型实例详解

    这篇文章主要介绍了GO语言的map类型实例详解,包括对map的创建,赋值,排序,删除,等操作需要的朋友可以参考下
    2022-12-12
  • Go 分布式链路追踪实现原理解析

    Go 分布式链路追踪实现原理解析

    分布式链路追踪作为解决分布式应用可观测问题的重要技术,愈发成为分布式应用不可缺少的基础设施,本文将详细介绍分布式链路的核心概念、架构原理和相关开源标准协议,并分享我们在实现无侵入 Go 采集 Sdk 方面的一些实践,需要的朋友可以参考下
    2022-06-06
  • golang数组和切片作为参数和返回值的实现

    golang数组和切片作为参数和返回值的实现

    本文主要介绍了golang数组和切片作为参数和返回值的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • Go语言实现JSON解析的方法详解

    Go语言实现JSON解析的方法详解

    在日常项目中,使用Json格式进行数据封装是比较常见的操作。本文将详细讲解如何利用Go语言实现JSON的解析,感兴趣的小伙伴可以学习一下
    2022-04-04
  • Go语言实现二分查找方法示例

    Go语言实现二分查找方法示例

    这篇文章主要为大家介绍了Go语言实现二分查找方法示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • Golang AGScheduler动态持久化任务调度的强大库使用实例

    Golang AGScheduler动态持久化任务调度的强大库使用实例

    这篇文章主要为大家介绍了Golang AGScheduler动态持久化任务调度的强大库使用实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • Go指针内存与安全性深入理解

    Go指针内存与安全性深入理解

    这篇文章主要为大家介绍了Go指针内存与安全性深入理解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • Go 计时器使用示例全面讲解

    Go 计时器使用示例全面讲解

    这篇文章主要为大家介绍了Go 计时器使用示例全面讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • Go语言如何在Web服务中实现优雅关机

    Go语言如何在Web服务中实现优雅关机

    在这篇文章中,我们将通过一个简单的例子来演示如何在 Go 语言中使用 Gin 框架实现优雅关机,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-11-11
  • Golang 1.16 中 Modules的主要变化更新

    Golang 1.16 中 Modules的主要变化更新

    这篇文章主要介绍了Golang 1.16 中 Modules的主要变化更新,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02

最新评论