当前位置: 首页 > news >正文

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数据存在耗时&#xff0c…...

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&#xff0…...

数学建模学习笔记-皮尔逊相关系数

内容:皮尔逊相关系数 一.概念:是一个和线性线关的相关性系数 1.协方差概念: 协方差受到量纲的影响因此需要剔除 2.相关性的误区 根据这个结论,我们在计算该系数之前需要确定是否为线性函数 二.相关性的计算 1.Matlab&#xff…...

随笔:集成学习:关于随机森林,梯度提升机的东拉西扯

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"><!-- 第一个参数为你的单选数组&#xff0c;第二个…...

linux中playbook的控制语句

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

MongoDB介绍

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

再看参数校验

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 写一个接口&#xff0c…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

stm32wle5 lpuart DMA数据不接收

配置波特率9600时&#xff0c;需要使用外部低速晶振...