binding

binding 中间件为 Flame 实例提供请求数据绑定和验证服务,支持的数据格式包括 Form、Multipart Form、JSON 和 YAML。

你可以在 GitHubbinding - 图1在新窗口打开 上阅读该中间件的源码或通过 pkg.go.devbinding - 图2在新窗口打开 查看 API 文档。

下载安装

Go 语言的最低版本要求为 1.16

  1. go get github.com/flamego/binding

用法示例

提示

本小结仅展示 binding 中间件的相关用法,如需了解验证模块的用法请移步 validatorbinding - 图3在新窗口打开 的文档。

绑定对象自身会被注入到请求上下文中以供后续的处理器使用,并额外提供 binding.Errorsbinding - 图4在新窗口打开 用于错误传递。

警告

禁止传递绑定对象的指针以确保每个处理器都能够获得对象的全新副本,以及避免潜在的副作用而导致的意外错误。

Form

binding.Formbinding - 图5在新窗口打开 会将请求数据以 application/x-www-form-urlencoded 的编码格式将其解析到绑定对象上,binding.Optionsbinding - 图6在新窗口打开 可以被用于配置该函数的行为。

绑定对象内的字段需要使用结构体标签 form 来表示与请求数据之间的绑定关系:

  • main.go
  • templates/home.tmpl
  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. "github.com/flamego/binding"
  6. "github.com/flamego/flamego"
  7. "github.com/flamego/template"
  8. "github.com/flamego/validator"
  9. )
  10. type User struct {
  11. FirstName string `form:"first_name" validate:"required"`
  12. LastName string `form:"last_name" validate:"required"`
  13. Age int `form:"age" validate:"gte=0,lte=130"`
  14. Email string `form:"email" validate:"required,email"`
  15. Hashtags []string `form:"hashtag"`
  16. }
  17. func main() {
  18. f := flamego.Classic()
  19. f.Use(template.Templater())
  20. f.Get("/", func(t template.Template) {
  21. t.HTML(http.StatusOK, "home")
  22. })
  23. f.Post("/", binding.Form(User{}), func(w http.ResponseWriter, form User, errs binding.Errors) {
  24. if len(errs) > 0 {
  25. var err error
  26. switch errs[0].Category {
  27. case binding.ErrorCategoryValidation:
  28. err = errs[0].Err.(validator.ValidationErrors)[0]
  29. default:
  30. err = errs[0].Err
  31. }
  32. w.WriteHeader(http.StatusBadRequest)
  33. _, _ = w.Write([]byte(fmt.Sprintf("Oops! Error occurred: %v", err)))
  34. return
  35. }
  36. w.WriteHeader(http.StatusOK)
  37. w.Write([]byte(fmt.Sprintf("User: %#+v", form)))
  38. })
  39. f.Run()
  40. }
  1. <form method="POST">
  2. <div>
  3. <label>First name:</label>
  4. <input type="text" name="first_name" value="John">
  5. </div>
  6. <div>
  7. <label>Last name:</label>
  8. <input type="text" name="last_name" value="Smith">
  9. </div>
  10. <div>
  11. <label>Age:</label>
  12. <input type="number" name="age" value="90">
  13. </div>
  14. <div>
  15. <label>Email:</label>
  16. <input type="email" name="email" value="john@example.com">
  17. </div>
  18. <div>
  19. <label>Hashtags:</label>
  20. <select name="hashtag" multiple>
  21. <option value="driver">Driver</option>
  22. <option value="developer">Developer</option>
  23. <option value="runner">Runner</option>
  24. </select>
  25. </div>
  26. <input type="submit" name="button" value="Submit">
  27. </form>

Multipart Form

binding.MultipartFormbinding - 图7在新窗口打开 会将请求数据以 multipart/form-data 的编码格式将其解析到绑定对象上,binding.Optionsbinding - 图8在新窗口打开 可以被用于配置该函数的行为。

绑定对象内的字段需要使用结构体标签 form 来表示与请求数据之间的绑定关系,用于存储上传文件的字段则必须声明为 *multipart.FileHeaderbinding - 图9在新窗口打开 类型:

  • main.go
  • templates/home.tmpl
  1. package main
  2. import (
  3. "fmt"
  4. "mime/multipart"
  5. "net/http"
  6. "github.com/flamego/binding"
  7. "github.com/flamego/flamego"
  8. "github.com/flamego/template"
  9. "github.com/flamego/validator"
  10. )
  11. type User struct {
  12. FirstName string `form:"first_name" validate:"required"`
  13. LastName string `form:"last_name" validate:"required"`
  14. Avatar *multipart.FileHeader `form:"avatar"`
  15. }
  16. func main() {
  17. f := flamego.Classic()
  18. f.Use(template.Templater())
  19. f.Get("/", func(t template.Template) {
  20. t.HTML(http.StatusOK, "home")
  21. })
  22. f.Post("/", binding.MultipartForm(User{}), func(w http.ResponseWriter, form User, errs binding.Errors) {
  23. if len(errs) > 0 {
  24. var err error
  25. switch errs[0].Category {
  26. case binding.ErrorCategoryValidation:
  27. err = errs[0].Err.(validator.ValidationErrors)[0]
  28. default:
  29. err = errs[0].Err
  30. }
  31. w.WriteHeader(http.StatusBadRequest)
  32. _, _ = w.Write([]byte(fmt.Sprintf("Oops! Error occurred: %v", err)))
  33. return
  34. }
  35. w.WriteHeader(http.StatusOK)
  36. w.Write([]byte(fmt.Sprintf("User: %#+v", form)))
  37. })
  38. f.Run()
  39. }
  1. <form enctype="multipart/form-data" method="POST">
  2. <div>
  3. <label>First name:</label>
  4. <input type="text" name="first_name" value="John">
  5. </div>
  6. <div>
  7. <label>Last name:</label>
  8. <input type="text" name="last_name" value="Smith">
  9. </div>
  10. <div>
  11. <label>Avatar:</label>
  12. <input type="file" name="avatar">
  13. </div>
  14. <input type="submit" name="button" value="Submit">
  15. </form>

JSON

binding.JSONbinding - 图10在新窗口打开 会将请求数据以 application/json 的编码格式将其解析到绑定对象上,binding.Optionsbinding - 图11在新窗口打开 可以被用于配置该函数的行为。

绑定对象内的字段需要使用结构体标签 json 来表示与请求数据之间的绑定关系:

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. "github.com/flamego/binding"
  6. "github.com/flamego/flamego"
  7. "github.com/flamego/validator"
  8. )
  9. type Address struct {
  10. Street string `json:"street" validate:"required"`
  11. City string `json:"city" validate:"required"`
  12. Planet string `json:"planet" validate:"required"`
  13. Phone string `json:"phone" validate:"required"`
  14. }
  15. type User struct {
  16. FirstName string `json:"first_name" validate:"required"`
  17. LastName string `json:"last_name" validate:"required"`
  18. Age uint8 `json:"age" validate:"gte=0,lte=130"`
  19. Email string `json:"email" validate:"required,email"`
  20. Addresses []*Address `json:"addresses" validate:"required,dive,required"`
  21. }
  22. func main() {
  23. f := flamego.Classic()
  24. f.Post("/", binding.JSON(User{}), func(w http.ResponseWriter, form User, errs binding.Errors) {
  25. if len(errs) > 0 {
  26. var err error
  27. switch errs[0].Category {
  28. case binding.ErrorCategoryValidation:
  29. err = errs[0].Err.(validator.ValidationErrors)[0]
  30. default:
  31. err = errs[0].Err
  32. }
  33. w.WriteHeader(http.StatusBadRequest)
  34. _, _ = w.Write([]byte(fmt.Sprintf("Oops! Error occurred: %v", err)))
  35. return
  36. }
  37. w.WriteHeader(http.StatusOK)
  38. w.Write([]byte(fmt.Sprintf("User: %#+v", form)))
  39. })
  40. f.Run()
  41. }

YAML

binding.YAMLbinding - 图12在新窗口打开 会将请求数据以 application/yaml 的编码格式将其解析到绑定对象上,binding.Optionsbinding - 图13在新窗口打开 可以被用于配置该函数的行为。

绑定对象内的字段需要使用结构体标签 yaml 来表示与请求数据之间的绑定关系:

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. "github.com/flamego/binding"
  6. "github.com/flamego/flamego"
  7. "github.com/flamego/validator"
  8. )
  9. type Address struct {
  10. Street string `yaml:"street" validate:"required"`
  11. City string `yaml:"city" validate:"required"`
  12. Planet string `yaml:"planet" validate:"required"`
  13. Phone string `yaml:"phone" validate:"required"`
  14. }
  15. type User struct {
  16. FirstName string `yaml:"first_name" validate:"required"`
  17. LastName string `yaml:"last_name" validate:"required"`
  18. Age uint8 `yaml:"age" validate:"gte=0,lte=130"`
  19. Email string `yaml:"email" validate:"required,email"`
  20. Addresses []*Address `yaml:"addresses" validate:"required,dive,required"`
  21. }
  22. func main() {
  23. f := flamego.Classic()
  24. f.Post("/", binding.YAML(User{}), func(w http.ResponseWriter, form User, errs binding.Errors) {
  25. if len(errs) > 0 {
  26. var err error
  27. switch errs[0].Category {
  28. case binding.ErrorCategoryValidation:
  29. err = errs[0].Err.(validator.ValidationErrors)[0]
  30. default:
  31. err = errs[0].Err
  32. }
  33. w.WriteHeader(http.StatusBadRequest)
  34. _, _ = w.Write([]byte(fmt.Sprintf("Oops! Error occurred: %v", err)))
  35. return
  36. }
  37. w.WriteHeader(http.StatusOK)
  38. w.Write([]byte(fmt.Sprintf("User: %#+v", form)))
  39. })
  40. f.Run()
  41. }