我正在 Gin 中编写一个中间件来记录请求正文以进行调试。为了多次读取正文,我需要使用 io.NopCloser 重新分配 c.Request.Body。这是我当前的实现:
return func(c *gin.Context) {
bodyBytes, _ := io.ReadAll(c.Request.Body)
_ = c.Request.Body.Close()
// Override the Close method of c.Request.Body
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
var bodyJSON map[string]interface{}
err := json.Unmarshal(bodyBytes, &bodyJSON)
if err != nil {
c.Next()
return
}
logrus.WithFields(logrus.Fields{
"method": c.Request.Method + "-request",
"path": c.Request.URL.Path,
"query": c.Request.URL.RawQuery,
"body": bodyJSON,
}).Info()
c.Next()
}
我担心 io.NopCloser 的使用,它会覆盖请求正文的
Close()
方法。这是否会导致数据泄漏,因为原始 Close()
方法被无操作 Close()
方法覆盖,并且在我将请求正文传递给另一个中间件后不执行任何操作来“关闭”请求正文?
我对 Golang 中的 IO 工作还比较陌生,所以我很感激任何关于更好方法的见解或建议。
对于服务器请求,您不需要关闭正文:
服务器将关闭请求正文。 HTTP 服务 处理程序不需要。
对于客户端请求,由于 HTTP 实现的特殊性,您需要关闭正文。当您需要副本时,应在可用时使用
Request.GetBody
。
您的代码与Gin中间件示例代码非常相似:
body, err := ioutil.ReadAll(r.Body)
if err != nil {
return "", err
}
r.Body = ioutil.NopCloser(bytes.NewBuffer(body))
所以我认为没问题。 “数据泄漏”主要是资源泄漏,因为垃圾收集器可以防止内存泄漏。您可能泄漏的是不必要的使用资源,例如您不再需要的数据库连接或不会终止的 goroutine。这里不存在这样的问题。