golang,go,博客,开源,编程

gin中间件打印请求、响应报文

Published on with 0 views and 0 comments

Gin 框架中,你可以通过自定义中间件来打印请求和响应报文。这在调试和日志记录中非常有用。下面是一个简单的示例,演示如何创建一个中间件来打印请求的相关信息,包括请求头、请求体、响应状态码等。

1. 打印请求信息的中间件

你可以编写一个中间件,捕获并打印每个请求的详细信息:

package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"time"

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

// 请求日志中间件
func RequestLogger() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取请求的开始时间
		start := time.Now()

		// 读取请求体(注意:请求体只能读取一次,所以需要进行复制)
		body, _ := ioutil.ReadAll(c.Request.Body)

		// 恢复请求体
		c.Request.Body = ioutil.NopCloser(bytes.NewReader(body))

		// 打印请求信息
		log.Printf("Request Method: %s", c.Request.Method)
		log.Printf("Request URL: %s", c.Request.URL)
		log.Printf("Request Headers: %+v", c.Request.Header)
		log.Printf("Request Body: %s", string(body))

		// 继续处理请求
		c.Next()

		// 打印响应信息
		duration := time.Since(start)
		log.Printf("Response Status: %d", c.Writer.Status())
		log.Printf("Duration: %v", duration)
	}
}

func main() {
	// 初始化Gin
	r := gin.Default()

	// 使用自定义的请求日志中间件
	r.Use(RequestLogger())

	// 示例路由
	r.POST("/example", func(c *gin.Context) {
		// 处理请求
		c.JSON(200, gin.H{
			"message": "Request received",
		})
	})

	// 启动服务器
	r.Run(":8080")
}

2. 代码解读

  • RequestLogger 中间件
    • 该中间件会打印请求的 方法(Method)URL请求头(Headers)请求体(Body)
    • ioutil.ReadAll(c.Request.Body) 用来读取请求体。由于请求体只能读取一次,读取后会丢失,所以需要将其恢复回去,供后续的处理使用。
    • 通过 c.Next() 来执行后续的请求处理。
    • 在请求处理完毕后,打印 响应状态码(Status)处理时长(Duration)
  • 日志输出
    • 请求的详细信息(如请求方法、URL、请求头和请求体)会被打印到标准日志中。
    • 响应的状态码以及处理的时长也会被记录,便于后期分析性能。

3. 启动应用

运行该程序后,当你访问 http://localhost:8080/example 并发送一个 POST 请求时,Gin 会打印出类似如下的日志:

Request Method: POST
Request URL: /example
Request Headers: map[Content-Type:[application/json] User-Agent:[Go-http-client/1.1]]
Request Body: {"name": "John"}
Response Status: 200
Duration: 42.12ms

4. 捕获响应内容

如果你还希望捕获和打印响应的内容,你可以通过 ginResponseWriter 进行一些额外的处理。例如,创建一个 ResponseWriter 包装器,来捕获和记录响应体内容。这里是一个扩展的示例,展示如何记录响应内容。

5. 捕获响应内容的中间件

package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"time"

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

// 自定义Writer以捕获响应内容
type ResponseWriterWrapper struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

func (rw *ResponseWriterWrapper) Write(b []byte) (int, error) {
	rw.body.Write(b)
	return rw.ResponseWriter.Write(b)
}

// 请求日志中间件,包含响应内容的捕获
func RequestLogger() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取请求的开始时间
		start := time.Now()

		// 读取请求体
		body, _ := ioutil.ReadAll(c.Request.Body)
		// 恢复请求体
		c.Request.Body = ioutil.NopCloser(bytes.NewReader(body))

		// 打印请求信息
		log.Printf("Request Method: %s", c.Request.Method)
		log.Printf("Request URL: %s", c.Request.URL)
		log.Printf("Request Headers: %+v", c.Request.Header)
		log.Printf("Request Body: %s", string(body))

		// 创建ResponseWriterWrapper来捕获响应体
		rw := &ResponseWriterWrapper{ResponseWriter: c.Writer, body: bytes.NewBufferString("")}
		c.Writer = rw

		// 继续处理请求
		c.Next()

		// 打印响应信息
		duration := time.Since(start)
		log.Printf("Response Status: %d", c.Writer.Status())
		log.Printf("Response Body: %s", rw.body.String())
		log.Printf("Duration: %v", duration)
	}
}

func main() {
	// 初始化Gin
	r := gin.Default()

	// 使用自定义的请求日志中间件
	r.Use(RequestLogger())

	// 示例路由
	r.POST("/example", func(c *gin.Context) {
		// 返回响应
		c.JSON(200, gin.H{
			"message": "Request received",
		})
	})

	// 启动服务器
	r.Run(":8080")
}

6. 响应内容捕获

通过 ResponseWriterWrapper,我们可以捕获 Gin 的响应内容,并在响应发送给客户端之前记录下来。输出日志将包括响应的状态码、响应体以及请求的处理时间。

例如,运行 POST 请求后,日志可能显示:

Request Method: POST
Request URL: /example
Request Headers: map[Content-Type:[application/json] User-Agent:[Go-http-client/1.1]]
Request Body: {"name": "John"}
Response Status: 200
Response Body: {"message":"Request received"}
Duration: 12.34ms

总结

通过自定义 Gin 中间件,你可以轻松地打印请求和响应的详细信息。这对于调试和性能监控非常有帮助。可以通过以下方式来优化日志内容:

  • 记录请求方法、URL、请求头、请求体。
  • 记录响应状态、响应体以及处理时间。
  • 为生产环境提供更详细的日志、调试信息或错误跟踪。

标题:gin中间件打印请求、响应报文
作者:mooncakeee
地址:http://blog.dd95828.com/articles/2025/01/07/1736218074102.html
联系:scotttu@163.com