golang,go,博客,开源,编程
在 Gin 框架中,你可以通过自定义中间件来打印请求和响应报文。这在调试和日志记录中非常有用。下面是一个简单的示例,演示如何创建一个中间件来打印请求的相关信息,包括请求头、请求体、响应状态码等。
你可以编写一个中间件,捕获并打印每个请求的详细信息:
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")
}
ioutil.ReadAll(c.Request.Body)
用来读取请求体。由于请求体只能读取一次,读取后会丢失,所以需要将其恢复回去,供后续的处理使用。c.Next()
来执行后续的请求处理。运行该程序后,当你访问 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
如果你还希望捕获和打印响应的内容,你可以通过 gin
的 ResponseWriter
进行一些额外的处理。例如,创建一个 ResponseWriter
包装器,来捕获和记录响应体内容。这里是一个扩展的示例,展示如何记录响应内容。
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")
}
通过 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 中间件,你可以轻松地打印请求和响应的详细信息。这对于调试和性能监控非常有帮助。可以通过以下方式来优化日志内容: