如何解决golang gin 使用 ShouldBindJson() 后丢失数据
g.Use(middleware.Auth)
g.POST("/show/detail",show.Detail)
在middleware.Auth
中,我使用ShouldBindJson(&data)
获取一些值来验证令牌,然后我再次使用ShouldBindJson(&reqData)
中的Detail
获取帖子数据,但什么也没获取.我尝试打印,发现 middleware.Auth()
中有数据,但 show.Detail
middleware.Auth
的一部分:
type authParams struct {
Username string `form:"username"`
Token string `form:"token"`
Timestamp int64 `form:"timestamp"`
}
func Auth(c *gin.Context) {
var auth authParams
_ = c.ShouldBindJSON(&auth)
fmt.Println(auth) // it output the data, not empty
// ....
}
show.Detail
的一部分
func Detail(c *gin.Context) {
type param struct {
ShowId uint64 `form:"show_id"`
}
//
var data param
c.Request.ParseForm()
//var data map[string]interface{}
e := c.ShouldBind(&data)
fmt.Println(data,e) // data is {0} and "e" output EOF
// ...
}
解决方法
在 Detail
处理程序中,不要在 c.Request.ParseForm()
之前调用 c.ShouldBind(&data)
。
ShouldBind
已经使用 ParseForm
在 HTTP POST 上调用 Content-Type: application/x-www-form-urlencoded
,这应该是您的情况,但是如果您已经用完了请求正文,则第二次调用将返回 EOF
填充 data
变量:
// binding/form.go
func (formBinding) Bind(req *http.Request,obj interface{}) error {
// This calls io.ReadAll on the body,which the second time returns io.EOF
if err := req.ParseForm(); err != nil {
return err
}
...
相反,要跨处理程序重用请求正文的内容,可以使用 c.ShouldBindBodyWith
(另请参阅 this),它将正文字节存储在 gin 上下文中,但是从 Gin 1.7.1 开始后表单绑定没有实现所需的接口。
因此,您可以手动读取和重置正文,也可以为您的用例实现 binding.BindingBody
。它可能如下所示:
var myFormBinding = postFormBodyBinding{ formBinding: binding.FormPost}
type postFormBodyBinding struct {
formBinding binding.Binding
}
// Just call binding.FormPost.Name
func (f postFormBodyBinding) Name() string {
return f.formBinding.Name()
}
// Just call binding.FormPost.Bind
func (f postFormBodyBinding) Bind(req *http.Request,obj interface{}) error {
return f.formBinding.Bind(req,obj)
}
func (f postFormBodyBinding) BindBody(b []byte,obj interface{}) error {
vs,err := url.ParseQuery(string(b))
if err != nil {
return err
}
switch data := obj.(type) {
case *authParams:
data.Token = vs.Get("token")
case *param:
data.ShowId,_ = strconv.ParseUint(vs.Get("show_id"),10,64)
default:
return errors.New("type not supported")
}
return nil
}
在您自己的 BindBody
实现中,您可以使用类型开关。由于您不是在编写一个必须使用任何类型的库,因此您不需要使用反射,您只需切换已接受的类型即可。
最后你这样称呼它:
c.ShouldBindBodyWith(&data,myFormBinding)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。