goravel: 🐛 [Bug] ctx.Request().Bind() get EOF

Before feedback (在反馈之前)

  • I’ve searched the existing Issues, Discussions and Google (我已经搜索了现有的 Issues, Discussions 和 Google)
  • The problem can be stably reproduced (这个问题可以被稳定复现)
  • The problem is generated after upgrading (问题是在升级之后产生的)

Operating System (操作系统)

Linux

Golang Version (Go 版本)

1.21.x

Goravel Version (Goravel 版本)

1.13.5

Describe The Problem (描述问题)

ctx.Request().Bind() always get EOF error. does it require all fields of struct to be added in the request json ?

Reproduction Code (复现代码或截图)

request json:

{
    "username" : "bc",
    "password" : "123456",
    "nickname" : "烟火",
    "email": "bc@a.b"
}

go struct definition:

type User struct {
	*orm.Model
	Username      string `form:"username" json:"username" gorm:"column:username"`
	Password      string `form:"password" json:"password" gorm:"column:password"`
	Status        int    `form:"status" json:"status" gorm:"column:status"`
	NickName      string `form:"nickName" json:"nickName" gorm:"column:nick_name"`
	AvatarURL     string `form:"avatarURL" json:"avatarURL" gorm:"column:avatar_url"`
	Sex           int    `form:"sex" json:"sex" gorm:"column:sex"`
	Email         string `form:"email" json:"email" gorm:"column:email"`
	MobileCountry string `form:"mobileCountry" json:"mobileCountry" gorm:"column:mobile_country"`
	Mobile        string `form:"mobile" json:"mobile" gorm:"column:mobile"`
	SelfIntro     string `form:"selfIntro" json:"selfIntro" gorm:"column:self_intro"`
	*orm.SoftDeletes
}

The code I used to bind:

ctx.Request().Bind(&user)

I’ve confirmed that I can get the request param via:

ctx.Request().Input("username", "")

The doc is simple: https://www.goravel.dev/the-basics/request.html#json-form-bind-struct

About this issue

  • Original URL
  • State: closed
  • Created 7 months ago
  • Comments: 26 (15 by maintainers)

Most upvoted comments

@kuchaguangjie I noticed you were using err = ctx.Request().Bind(&dummy), it should be changed to err = validator.Bind(&dummy), because the request.Body had been read. I’ll check if we can use ctx.Request().Bind in this case, but it’s not a bug, you should change it for now.

fiber is good, do you have a link of how to use fiber, I checked the doc, didn’t found it.

See https://github.com/goravel/fiber

Could you please copy your whole code here? I’ll try it locally.

All you need is to add a validation like my above comment before bind().

Here is the register() method of user controller:


func (r *UserController) Register(ctx http.Context) http.Response {
	// TODO: enable validation, after bug fixed. (Refer: https://github.com/goravel/goravel/issues/331#issuecomment-1837513759)
	/*
		// validate
		validator, err := ctx.Request().Validate(map[string]string{
			"username": "required|min_len:2|max_len:30",
			"password": "required|min_len:6|max_len:30",
			// TODO: validate email / mobile.
		})
		if err != nil {
			facades.Log().Error(err.Error())
			return ctx.Response().String(500, err.Error())
		}
		if validator.Fails() {
			facades.Log().Warning(validator.Errors())
			return ctx.Response().Json(400, validator.Errors().All())
		}
	*/

	// bind param.
	user := models.NewUser()
	err := ctx.Request().Bind(user)
	facades.Log().Info(user)
	if err != nil {
		facades.Log().Error(err.Error())
		return ctx.Response().String(500, err.Error())
	}

	// check username exists.
	var ec int64
	err = facades.Orm().Query().Model(user).Where("username=?", user.Username).Count(&ec)
	if err != nil {
		facades.Log().Error(err.Error())
		return ctx.Response().String(400, err.Error())
	}
	if ec > 0 {
		return ctx.Response().String(400, "username already exists")
	}
	// TODO: check email exists.
	// TODO: check mobile+mobileCountry exists.

	// prepare data,
	user.Balance = decimal.Zero
	password, err := facades.Hash().Make(user.Password) // hash password.
	if err != nil {
		facades.Log().Error(err.Error())
		return ctx.Response().String(500, err.Error())
	}
	user.Password = password
	user.CurrencyCode = models.DefaultCurrencyCode
	// TODO: use username as nickName if no nickName specified ?

	// save user.
	err = facades.Orm().Query().Save(user)
	if err != nil {
		facades.Log().Error(err.Error())
		return ctx.Response().String(500, err.Error())
	}
	return ctx.Response().Success().Json(http.Json{
		"id": user.ID,
	})
}

It works now, but if you uncomment the validation part, it will get EOF error.

The user model I already passed as above, it doesn’t matter actually. A model with a single field that do both validation & bind can reveal the error.

图片

I can’t reproduce it, can you provide a minimal reproduction example?