你是不是在中间件里面ShouldBind报错EOF
-
在 Gin 框架中,当多次调用 ShouldBind() 或 ShouldBindJSON() 方法时,会导致请求体的数据流被读取多次,从而出现 “EOF” 错误。
-
这是因为在 HTTP 请求中,请求体的数据流是按顺序读取的。每次调用 ShouldBind() 或 ShouldBindJSON() 方法都会尝试读取请求体的数据流,但在第一次读取后,数据流已经被消耗完毕,所以后续的读取操作将会返回 “EOF” 错误。
-
为了避免这个问题,你可以在第一次调用 ShouldBind() 或 ShouldBindJSON() 方法后,将请求体的数据流保存下来,并重新设置到 Request.Body 中,以便后续的绑定操作可以重新读取请求体的数据。
-
参考这篇文章改造的代码:https://learnku.com/articles/69068
下面是我的解决代码
package middleware
import (
"bytes"
"fmt"
"io"
"xxxx/common/global"
"strings"
"github.com/gin-gonic/gin"
)
// 获取参数集合
func RequestParams(ctx *gin.Context) {
bindParams := map[string]any{}
if ctx.Request.Method == "POST" {
contextType := ctx.Request.Header.Get("Content-Type")
requestBody, err := ctx.GetRawData()
if err != nil {
global.Logger.Errorf("GetRawData,err: %v ", err)
return
}
// 重置请求体,以便后续的中间件和处理程序可以正常读取
ctx.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
defer func() {
ctx.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
}()
// 绑定参数
if contextType == "application/json" {
err := ctx.ShouldBind(&bindParams)
if err != nil { // 报错
global.Logger.Errorf("获取参数异常: %v ", err)
return
}
} else {
_ = ctx.Request.ParseMultipartForm(32 << 20)
if len(ctx.Request.PostForm) > 0 {
for k, v := range ctx.Request.PostForm {
bindParams[k] = v[0]
}
}
}
}
ctx.Set("RequestParams", bindParams)
}
func JoinParamsStr(ctx *gin.Context) string {
params := ctx.GetStringMap("RequestParams")
var newparams []string
if len(params) > 0 {
for k, v := range params {
newparams = append(newparams, fmt.Sprintf("%s=%v", k, v))
}
}
return strings.Join(newparams, "&")
}
func GetRequestParams(ctx *gin.Context) map[string]any {
return ctx.GetStringMap("RequestParams")
}
router.go
// 引入中间件
r.Use(middleware.RequestParams)