Table of Contents
请求数据无法二次获取
bodyByts, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.String(http.StatusBadRequest, err.Error())
c.Abort()
}
// 回填请求数据,便于再次获取
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyByts))
同时处理 GET 和 POST 请求
type Person struct {
Name string `form:"name"`
Address string `form:"address"`
Birthday time.Time `form:"birthday"`
}
func main() {
r := gin.Default()
r.GET("/testing", testing)
r.POST("/testing", testing)
}
func testing(c *gin.Context) {
var person Person
// ShouldBind 会根据请求类型(content-type)自动转换参数到指定结构体内
if err := c.ShouldBind(&person); err == nil {
// do something
}
}
参数验证
结构体验证
// https://pkg.go.dev/gopkg.in/go-playground/validator.v8#section-readme
type Person struct {
Age int `form:"age" binding:"required,gt=10"`
Name string `form:"name" binding:"required"`
Address string `from:"address" binding:"required"`
}
自定义验证
validator.v8 是支持自定义验证的。
type Booking struct {
CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`
CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"`
}
// 定义验证方法
func bookableDate(*validator.Validate, reflect.Value, reflect.Value, field reflect.Value, reflect.Type, reflect.Kind, string) bool {
if date,ok := field.Interface().(time.Time);ok {
today := time.Now()
if date.Unix() > today.Unix() {
return true
}
}
return false
}
func main() {
r := gin.Default()
// 注册验证方法
if v,ok := binding.Validator.Engine().(*validator.Validate);ok {
v.RegisterValidation("bookabledate", bookableDate)
}
}
多语言验证
package main
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/zh"
"github.com/go-playground/universal-translator"
"gopkg.in/go-playground/validator.v9"
en2 "gopkg.in/go-playground/validator.v9/translations/en"
zh2 "gopkg.in/go-playground/validator.v9/translations/zh"
"net/http"
"time"
)
type Booking struct {
CheckIn time.Time `form:"check_in" validate:"required,bookableDate" time_format:"2006-01-02"`
CheckOut time.Time `form:"check_out" validate:"required,gtfield=CheckIn" time_format:"2006-01-02"`
}
func main(){
r := gin.Default()
zhTranslate := zh.New()
enTranslate := en.New()
Uni := ut.New(zhTranslate, enTranslate)
validate := validator.New()
_ = validate.RegisterValidation("bookableDate", bookableDate)
r.GET("/bookable", func(c *gin.Context) {
locale := c.DefaultQuery("locale", "zh")
trans, _ := Uni.GetTranslator(locale)
switch locale {
case "zh":
_ = validate.RegisterTranslation("bookableDate", trans, registerBookableDateTranslation, bookableDateTranslation)
_ = zh2.RegisterDefaultTranslations(validate, trans)
break
case "en":
_ = en2.RegisterDefaultTranslations(validate, trans)
break
default:
_ = validate.RegisterTranslation("bookableDate", trans, registerBookableDateTranslation, bookableDateTranslation)
_ = zh2.RegisterDefaultTranslations(validate, trans)
}
var book Booking
if err := c.ShouldBind(&book); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
c.Abort()
return
}
if err := validate.Struct(book); err != nil {
errs := err.(validator.ValidationErrors)
var sliceErrs []string
for _, v := range errs {
sliceErrs = append(sliceErrs, v.Translate(trans))
}
c.JSON(http.StatusInternalServerError, gin.H{
"error": sliceErrs,
})
c.Abort()
return
}
c.JSON(http.StatusOK, gin.H{
"message": "OK",
"booking": book,
})
})
_ = r.Run()
}
func bookableDate(fl validator.FieldLevel) bool {
if date, ok := fl.Field().Interface().(time.Time); ok {
today := time.Now()
if date.Unix() > today.Unix() {
return true
}
}
return false
}
func registerBookableDateTranslation(ut ut.Translator) error {
return ut.Add("bookableDate", "{0} 日期必须大于当天日期!", true)
}
func bookableDateTranslation(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("bookableDate", fe.Field())
return t
}