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

Gin 优雅打印请求与回包内容

文章目录

  • 1.Gin 的 Middleware
  • 2.使用 Middleware 打印请求与回包内容
  • 3.多次读取请求 Body 的问题
  • 4.多次读取响应 Body 的问题
  • 5.小结
  • 参考文献

在开发 Web 应用程序时,难免不会遇到功能或性能等问题。为了快速定位问题,需要打印请求和响应的内容。

本文将介绍如何使用 Gin 框架来优雅地打印请求和响应的内容。

1.Gin 的 Middleware

在 Gin 框架中,中间件是一种用于拦截 HTTP 请求和响应的机制。中间件函数可以在请求到达处理程序之前或之后执行某些操作,例如打印请求和响应的内容、验证请求数据等。

Gin 框架提供了一种简单的方法来定义和使用中间件。中间件函数需要满足以下条件:

  • 函数的签名必须是 func(c *gin.Context),其中 c 是 Gin 框架中的上下文对象。
  • 函数可以执行任何操作,但是必须调用 c.Next() 方法来继续执行请求处理程序和其他中间件函数。
  • 如果需要在请求处理程序之后执行某些操作,可以在调用 c.Next() 之后执行。

2.使用 Middleware 打印请求与回包内容

下面是一个使用 Gin 中间件来打印请求和响应内容的示例代码:

func Logger() gin.HandlerFunc {return func(c *gin.Context) {// 记录请求时间start := time.Now()// 打印请求信息reqBody, _ := c.GetRawData()fmt.Printf("[INFO] Request: %s %s %s\n", c.Request.Method, c.Request.RequestURI, reqBody)// 执行请求处理程序和其他中间件函数c.Next()// 记录回包内容和处理时间end := time.Now()latency := end.Sub(start)respBody := string(c.Writer.Body.Bytes())fmt.Printf("[INFO] Response: %s %s %s (%v)\n", c.Request.Method, c.Request.RequestURI, respBody, latency)}
}func main() {r := gin.Default()// 注册中间件r.Use(Logger())r.GET("/", func(c *gin.Context) {c.String(http.StatusOK, "Hello, World!")})r.Run(":8080")
}

上面的代码定义了一个中间件,用来记录请求和回包内容。在中间件中,我们首先记录请求的时间和请求内容,然后调用 c.Next() 继续处理请求。在请求处理完成后,我们记录回包内容和处理时间。最后,我们使用 gin.Default() 函数来创建一个 Gin 引擎实例,并注册路由和中间件。启动服务后,我们可以访问http://localhost:8080/hello查看请求和回包的内容。

3.多次读取请求 Body 的问题

实际上,上面的做法会有问题。

在中间件中读取了请求的 Body,如果在接口处理函数中再次读取 Body,会导致 Body 被读取两次,从而出现问题。 因为在读取 Body 后,Body 的指针会被移到末尾,第二次读取时就无法再次读取到内容。

那么 Gin 如何正确多次读取 http request body 的内容呢?

解决思路: 由于 Request.Body 为公共变量,我们在对原有的 buffer 读取完成后,只要手动创建一个新的 buffer 然后以同样接口形式替换掉原有的 Request.Body 即可。

reqBytes, _ := c.GetRawData()// 请求包体写回。
if len(reqBytes) > 0 {c.Request.Body = io.NopCloser(bytes.NewBuffer(reqBytes))
}

在 Go 语言中,io.NopCloser 函数返回一个实现 io.ReadCloser 接口的对象,这个对象可以包装任何实现 io.Reader 接口的对象,并提供了一个空的 Close 方法。这个方法的作用就是什么也不做,仅仅是返回一个 nil 的 error。

通常情况下,我们会使用 io.ReadCloser 接口读取数据,并在读取完成后关闭相关资源,例如打开的文件句柄或者网络连接等。但是在某些场景下,我们希望读取数据,但是并不想关闭相关资源,比如在数据读取完成后还需要进行一些其他操作,或者需要多次读取同一个资源等。

这时候,就可以使用 io.NopCloser 函数将一个实现了 io.Reader 接口的对象包装成一个实现了 io.ReadCloser 接口的对象,并在 Close 方法中什么也不做。这样就可以在读取数据后不关闭相关资源,从而方便进行其他操作或者多次读取同一个资源。

4.多次读取响应 Body 的问题

同样地,在中间件中读取响应 Body 的问题是,它会使得缓冲区被读取完毕,指针指向了缓冲区的末尾,而后续的代码再次读取 Body 时,指针已经到了缓冲区的末尾,无法再次读取。

为了避免这个问题,我们可以使用一个自定义的 ResponseWriter 来替换 Gin 默认的 ResponseWriter。自定义的 ResponseWriter 可以将响应 Body 写入到一个内存缓冲区中,并在中间件中获取响应 Body 并记录日志。

下面是一个完整的可以在日志中间件中读取请求与响应 Body 的示例。

// CustomResponseWriter 封装 gin ResponseWriter 用于获取回包内容。
type CustomResponseWriter struct {gin.ResponseWriterbody *bytes.Buffer
}func (w CustomResponseWriter) Write(b []byte) (int, error) {w.body.Write(b)return w.ResponseWriter.Write(b)
}// 日志中间件。
func Logger() gin.HandlerFunc {return func(c *gin.Context) {// 记录请求时间start := time.Now()// 使用自定义 ResponseWritercrw := &CustomResponseWriter{body:           bytes.NewBufferString(""),ResponseWriter: c.Writer,}c.Writer = crw// 打印请求信息reqBody, _ := c.GetRawData()fmt.Printf("[INFO] Request: %s %s %s\n", c.Request.Method, c.Request.RequestURI, reqBody)// 执行请求处理程序和其他中间件函数c.Next()// 记录回包内容和处理时间end := time.Now()latency := end.Sub(start)respBody := string(crw.body.Bytes())fmt.Printf("[INFO] Response: %s %s %s (%v)\n", c.Request.Method, c.Request.RequestURI, respBody, latency)}
}

5.小结

在本文中,我们介绍了为什么要打印请求与回包内容,以及如何使用 Gin 的 Middleware 功能来打印请求和回包内容。通过打印请求和回包内容,我们可以更好地了解 API 的执行过程,并且可以快速定位问题。


参考文献

OpenAI ChatGPT
Using middleware | Gin Web Framework
如何让gin正确多次读取http request body内容- 掘金
如何让gin 正确读取http response body 内容,并多次使用- 掘金

相关文章:

Gin 优雅打印请求与回包内容

文章目录1.Gin 的 Middleware2.使用 Middleware 打印请求与回包内容3.多次读取请求 Body 的问题4.多次读取响应 Body 的问题5.小结参考文献在开发 Web 应用程序时,难免不会遇到功能或性能等问题。为了快速定位问题,需要打印请求和响应的内容。本文将介绍…...

关于k8s中ETCD集群备份灾难恢复的一些笔记

写在前面 集群电源不稳定,或者节点动不动就 宕机,一定要做好备份,ETCD 的快照文件很容易受影响损坏。重置了很多次集群,才认识到备份的重要博文内容涉及 etcd 运维基础知识了解静态 Pod 方式 etcd 集群灾备与恢复 Demo定时备份的任务编写二进…...

【设计模式之美 设计原则与思想:设计原则】19 | 理论五:控制反转、依赖反转、依赖注入,这三者有何区别和联系?

关于 SOLID 原则,我们已经学过单一职责、开闭、里式替换、接口隔离这四个原则。今天,我们再来学习最后一个原则:依赖反转原则。在前面几节课中,我们讲到,单一职责原则和开闭原则的原理比较简单,但是&#x…...

2023年全国最新高校辅导员精选真题及答案13

百分百题库提供高校辅导员考试试题、辅导员考试预测题、高校辅导员考试真题、辅导员证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 一、单选题 131.下列不属于我国国土空间具有的特点的是() A.水资…...

【XXL-JOB】XXL-JOB定时处理视频转码

【XXL-JOB】XXL-JOB定时处理视频转码 文章目录【XXL-JOB】XXL-JOB定时处理视频转码1. 准备工作1.1 高级配置1.2 分片广播2. 需求分析2.1 作业分片方案2.2 保证任务不重复执行2.2.1 保证幂等性3. 视频处理业务流程3.1 添加待处理任务3.2 查询待处理任务3.3 更新任务状态3.4 工具…...

optuna用于pytorch的轻量级调参场景和grid search的自定义设计

文章目录0. 背景:why optuna0.1 插播一个简单的grid search0.2 参考1. Optuna1.1 a basic demo与部分参数释义1.2 random的问题1.3 Objective方法类2. Optuna与grid search4. optuna的剪枝prune5. optuna与可视化6. 未完待续0. 背景:why optuna 小模型参…...

语法篇--汇编语言先导浅尝

一、相关概念 1.机器语言 机器语言(Machine Language)是一种计算机程序语言,由二进制代码(0和1)组成,可被计算机直接执行。机器语言是计算机硬件能够理解和执行的唯一语言。 机器语言通常由一系列的指令组…...

【ID:17】【20分】A. DS顺序表--类实现

时间限制1秒内存限制128兆字节题目描述用C语言和类实现顺序表属性包括:数组、实际长度、最大长度(设定为1000)操作包括:创建、插入、删除、查找类定义参考输入第1行先输入n表示有n个数据,即n是实际长度;接着输入n个数据…...

【java web篇】Tomcat的基本使用

📋 个人简介 💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜📝 个人主页:馆主阿牛🔥🎉 支持我:点赞👍收藏⭐️留言&#x1f4d…...

MySQL实战解析底层---行锁功过:怎么减少行锁对性能的影响

目录 前言 从两阶段锁说起 死锁和死锁检测 前言 MySQL 的行锁是在引擎层由各个引擎自己实现的但并不是所有的引擎都支持行锁,比如MyISAM 引擎就不支持行锁不支持行锁意味着并发控制只能使用表锁,对于这种引擎的表,同一张表上任何时刻只能有…...

初识STM32单片机

目录 初识STM32单片机 什么是单片机? STM系列单片机命名规则 STM32F103C8T6单片机简介 标准库与HAL库区别 通用输入输出端口GPIO 什么是GPIO? 定义 命名规则 内部框架图 推挽输出与开漏输出 如何点亮一颗LED灯 编程实现点灯 按键点亮LED灯…...

数据结构与算法系列之单链表

💗 💗 博客:小怡同学 💗 💗 个人简介:编程小萌新 💗 💗 如果博客对大家有用的话,请点赞关注再收藏 🌞 这里写目录标题test.hSList.h注意事项一级指针与二级指针的使用assert的使用空…...

MySQL基础

本单元目标 ​ 一、为什么要学习数据库 ​ 二、数据库的相关概念 ​ DBMS、DB、SQL ​ 三、数据库存储数据的特点 ​ 四、初始MySQL ​ MySQL产品的介绍 ​ MySQL产品的安装 ★ ​ MySQL服务的启动和停止 ★ ​ MySQL服务的登录和退出 ★ ​ MySQL的常见命令和语法规范 ​ 五、…...

面试热点题:环形链表及环形链表寻找环入口结点问题

环形链表 问题: 给你一个链表的头节点 head ,判断链表中是否有环。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接…...

【算法】DFS与BFS

作者:指针不指南吗 专栏:算法篇 🐾题目的模拟很重要!!🐾 文章目录1.区别2.DFS2.1 排列数字2.2 n-皇后问题3.BFS3.1走迷宫1.区别 搜索类型数据结构空间用途过程DFSstackO( n )不能用于最短路搜索到最深处&a…...

湖州银行冲刺A股上市:计划募资约24亿元,资产质量水平较高

3月4日,湖州银行股份有限公司(下称“湖州银行”)递交招股书,准备在上海证券交易所主板上市。本次冲刺上市,湖州银行计划募资23.98亿元,将在扣除发行费用后全部用于补充该行资本金。 湖州银行在招股书中表示…...

高性能网络I/O框架-netmap源码分析

前几天听一个朋友提到这个netmap,看了它的介绍和设计,确实是个好东西。其设计思想与业界不谋而合——因为为了提高性能,几个性能瓶颈放在那里,解决方法自然也是类似的。 netmap的出现,它既实现了一个高性能的网络I/O框…...

SpringBoot监听机制-以及使用

11-SpringBoot事件监听 Java中的事件监听机制定义了以下几个角色: ①事件:Event,继承 java.util.EventObject 类的对象 ②事件源:Source ,任意对象Object ③监听器:Listener,实现 java.util…...

若依学习——定时任务代码逻辑 详细梳理(springboot整合Quartz)

springboot整合Quartz关于若依定时任务的使用可以去看视频默认定时任务的使用关于springboot整合quartz的整合参考(150条消息) 定时任务框架Quartz-(一)Quartz入门与Demo搭建_quarzt_是Guava不是瓜娃的博客-CSDN博客(150条消息) SpringBoot整合Quartz_springboot quartz_桐花思…...

C++---最长上升子序列模型---拦截导弹(每日一道算法2023.3.4)

注意事项: 本题为"线性dp—最长上升子序列的长度"的扩展题,这里只讲贪心思路,dp去这个看。 题目: 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。 但是这种导弹拦截系统有一个缺陷:虽然它…...

【机器学习面试】百面机器学习笔记和问题总结+扩展面试题

第1章 特征工程 1、为什么需要对数值类型的特征做归一化? (1)消除量纲,将所有特征统一到一个大致相同的区间范围,使不同指标之间具由可比性; (2)可以加快梯度下降收敛的速度&#…...

【2021.12.28】ctf逆向中的迷宫问题(含exe及wp)

【2021.12.28】ctf逆向中的迷宫问题(含exe及wp) 文章目录【2021.12.28】ctf逆向中的迷宫问题(含exe及wp)1、迷宫简介(1)简单例子(2)一般的迷宫代码2、二维迷宫(1&#xf…...

WSL2使用Nvidia-Docker实现深度学习环境自由部署

1. Win11 显卡驱动的安装 注意:WSL2中是不需要且不能安装任何显卡驱动的,它的显卡驱动完全依赖于 Win11 中的显卡驱动,因此我们只需要安装你显卡对应的 Win11 版本显卡驱动版本(必须是 Win11 版本的驱动),…...

SpringBoot入门 - 配置热部署devtools工具

在SpringBoot开发调试中,如果我每行代码的修改都需要重启启动再调试,可能比较费时间;SpringBoot团队针对此问题提供了spring-boot-devtools(简称devtools)插件,它试图提升开发调试的效率。准备知识点什么是…...

CANFDNET-200U-UDP配置与数据收发控制

一、启动ZCANPRP,打开设备管理页面,选择类型CANFDNET-200U-UDP,如图1 图1 二、打开设备,启动,在相应页面如图2,配置协议,CANFD 加速,本地端口,IP地址,工作端口。 图2 三、发送相应数…...

嵌入式中backtrace的使用

大家好,我是bug菌~ backtrace主要用于调试程序时,能够打印出程序在运行过程中的函数调用栈,以帮助开发者快速定位程序出现异常或崩溃的原因。 通过backtrace的输出,开发者可以了解程序在哪个函数出现问题&#xff0c…...

CV学习笔记-Faster-RCNN

Faster R-CNN 文章目录Faster R-CNN1. 目标检测算法1.1 计算机视觉有五大应用1.2 目标检测任务1.3 目标检测算法概述2. 边框回归(Bounding-Box regression)2.1 IoU2.2 统计学中的指标2.3 边框回归3. Faster-RCNN网络3.1 Conv layers3.2 Region Proposal …...

大型三甲医院云HIS系统源码 强大的电子病历+完整文档

医院HIS系统源码云HIS系统:SaaS运维平台多医院入驻强大的电子病历完整文档 有源码,有演示 一、系统概述 采用主流成熟技术,软件结构简洁、代码规范易阅读,SaaS应用,全浏览器访问前后端分离,多服务协同&am…...

如何使用Spring Cloud搭建高可用的Elasticsearch集群?详解Elasticsearch的安装与配置及Spring Boot集成的实现

Spring Cloud 是一个基于 Spring Boot 的微服务框架,它提供了一系列组件和工具,方便开发人员快速搭建和管理分布式系统。Elasticsearch 是一个开源的全文搜索引擎,也是一个分布式、高可用的 NoSQL 数据库。本篇博客将详细讲解如何使用 Spring…...

phpinfo包含临时文件Getshell全过程及源码

目录 前言 原理 漏洞复现 靶场环境 源码 复现过程 前言 PHP LFI本地文件包含漏洞主要是包含本地服务器上存储的一些文件,例如session文件、日志文件、临时文件等。但是,只有我们能够控制包含的文件存储我们的恶意代码才能拿到服务器权限。假如在服…...