Golang实践录:gin绑定解析json的两种方法
本文介绍 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 testimport ("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_tvar err errorctxType := ctx.Request.Header.Get("Content-Type")if strings.Contains(ctxType, "application/json") { // 纯 json// 先获取总的jsonif 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_tvar err errorvar reqbuffer []bytectxType := ctx.Request.Header.Get("Content-Type")if strings.Contains(ctxType, "application/json") { // 纯 jsonreqbuffer, 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数据并解析的2种方法。 起因及排查 某微服务工程,最近测试发现请求超时,由于特殊原因超时较短,如果请求处理耗时超过1秒则认为失败。排查发现,可能是gin接收解析json数据存在耗时,…...

Hypervisor Display架构
Hypervisor Display架构部分 1,所有LA侧的APP与显示相关的调用最终都会交由SurfaceFlinger处理 2,SurfaceFlinger会最终调用android.hardware.graphics.composer2.4-service服务 3,android.hardware.graphics.composer2.4-service服务会调用G…...

基于ssm二手车交易平台的设计论文
摘 要 进入21世纪网络和计算机得到了飞速发展,并和生活进行了紧密的结合。目前,网络的运行速度以达到了千兆,覆盖范围更是深入到生活中的角角落落。这就促使二手交易网站的发展。二手交易网站可以实现远程购物,远程选择喜欢的商品…...

IDEA 设置 SpringBoot logback 彩色日志(附配置文件)
1、背景说明 最开始使用 SpringBoot 时,控制台日志是带彩色的,让人眼前一亮😄 后来彩色莫名丢失,由于影响不大,一直没有处理。 2、配置彩色 最近找到了解决方法(其实是因为自定义 logback.xml࿰…...

数学建模学习笔记-皮尔逊相关系数
内容:皮尔逊相关系数 一.概念:是一个和线性线关的相关性系数 1.协方差概念: 协方差受到量纲的影响因此需要剔除 2.相关性的误区 根据这个结论,我们在计算该系数之前需要确定是否为线性函数 二.相关性的计算 1.Matlabÿ…...
随笔:集成学习:关于随机森林,梯度提升机的东拉西扯
1.集成学习 这里不会描述算法过程。 当我们有许多学习器对同一个任务做出判断,他们预测的概率可能各不相同,比如预测一个男生(小徐)会不会喜欢另一个女生(小雪),支持向量机算出来小徐爱上小雪的概率是0.8,朴素贝叶斯认为是0.3&a…...

多款实用个人年终总结模板,助力你的年度汇报!
临近年末,相信很多职场人这阵子都在忙着撰写个人年终总结,这份材料是对自己过去一年的工作进行的回顾和总结。撰写年终总结,其实也是一个非常重要的自我反思过程,可以帮助我们明确自己的目标,找出需要改进的地方&#…...

【C语言】动态内存管理基础知识——动态通讯录,如何实现通讯录容量的动态化
引言 动态内存管理的函数有:malloc,calloc,ralloc,free,本文讲解动态内存函数和使用,如何进行动态内存管理,实现通讯录联系人容量的动态化,对常见动态内存错误进行总结。 ✨ 猪巴戒:个人主页✨ 所属专栏:《C语言进阶》…...
Centos9(Stream)配置Let‘s Encrypt (免费https证书)
1. 安装snap,用来安装certbot: sudo dnf install epel-release sudo dnf upgrade sudo yum install snapd sudo systemctl enable --now snapd.socket sudo ln -s /var/lib/snapd/snap /snap snap install core snap refresh core 2. 安装 certbot命令…...
Spring之事务(2)
学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博客但无从下手,急需…...

嵌入式科普(5)ARM GNU Toolchain相关概念和逻辑
一、目的/概述 二、资料来源 三、逻辑和包含关系 四、Arm GNU Toolchain最常用的命令 嵌入式科普(5)ARM GNU Toolchain相关概念和逻辑 一、目的/概述 对比高集成度的IDE(MDK、IAR等),Linux开发需要自己写Makefile等多种脚本。eclipse、Visual Studio等需要了解预处…...

Elasticsearch:什么是文本分类?
文本分类定义 - text classification 文本分类是一种机器学习,它将文本文档或句子分类为预定义的类或类别。 它分析文本的内容和含义,然后使用文本标签为其分配最合适的标签。 文本分类的实际应用包括情绪分析(确定评论中的正面或负面情绪&…...

指针(3)
C语言昂,指针昂,最喜欢的一集,小时候学这一课我直接取地址了。上一篇博客给大家讲解了不同类型的指针变量的大小,今天来给大家讲解一下根据其所产生的一些性质。(往期回顾:指针(2)-C…...

外汇天眼:我碰到外汇投资骗局了吗?学会这5招,轻松识别外汇诈骗黑平台!
近年来外汇市场因为交易量大、流动性大、不容易被控盘、品种简单、风险相对低等特色,因此吸引不少投资人青睐,成为全球金融市场的热门选择。 然而,市面上充斥许多诈骗集团设立的黑平台,也打着投资外汇的名义行骗,不免会…...

一文解析子网掩码和默认网关,成为网络设置达人
随着互联网的普及,越来越多的人开始接触并使用电脑和网络。然而,对于很多初学者来说,网络设置中的子网掩码和默认网关是两个相对陌生的概念。今天,我们就来深入解析这两个概念,让你轻松掌握网络设置技巧! …...

二分查找法详解(6种变形)
前言 在之前的博客中,我给大家介绍了最基础的二分查找法(没学的话点我点我!) 今天我将带大家学习二分法的六种变形如何使用,小伙伴们,快来开始今天的学习吧! 文章目录 1,查找第一个…...

uniapp uview 页面多个select组件回显处理,默认选中
<view class"add-item column space-around" click"selectClick(1)"><text class"w-s-color-3 f-28">商品分类</text><view class"w-100 space-between"><!-- 第一个参数为你的单选数组,第二个…...

linux中playbook的控制语句
本章主要介绍 playbook中的控制语句。 使用 when 判断语句 block-rescue判断 循环语句 一个play中可以包含多个task,如果不想所有的task全部执行,可以设置只有满足某个 条件才执行这个task,不满足条件则不执行此task。本章主要讲解when 和 …...

MongoDB介绍
一、MongoDB介绍 1.1 mongoDB介绍 MongoDB 是由C语言编写的,是一个基于分布式文件存储的开源数据库系统。 在高负载的情况下,添加更多的节点,可以保证服务器性能。 MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。 MongoDB …...

再看参数校验
作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 写一个接口,…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...
WEB3全栈开发——面试专业技能点P7前端与链上集成
一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染(SSR)与静态网站生成(SSG) 框架,由 Vercel 开发。它简化了构建生产级 React 应用的过程,并内置了很多特性: ✅ 文件系…...
用递归算法解锁「子集」问题 —— LeetCode 78题解析
文章目录 一、题目介绍二、递归思路详解:从决策树开始理解三、解法一:二叉决策树 DFS四、解法二:组合式回溯写法(推荐)五、解法对比 递归算法是编程中一种非常强大且常见的思想,它能够优雅地解决很多复杂的…...

高端性能封装正在突破性能壁垒,其芯片集成技术助力人工智能革命。
2024 年,高端封装市场规模为 80 亿美元,预计到 2030 年将超过 280 亿美元,2024-2030 年复合年增长率为 23%。 细分到各个终端市场,最大的高端性能封装市场是“电信和基础设施”,2024 年该市场创造了超过 67% 的收入。…...
背包问题双雄:01 背包与完全背包详解(Java 实现)
一、背包问题概述 背包问题是动态规划领域的经典问题,其核心在于如何在有限容量的背包中选择物品,使得总价值最大化。根据物品选择规则的不同,主要分为两类: 01 背包:每件物品最多选 1 次(选或不选&#…...