requests.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package httpx
  2. import (
  3. "io"
  4. "net/http"
  5. "strings"
  6. "sync/atomic"
  7. "github.com/zeromicro/go-zero/core/mapping"
  8. "github.com/zeromicro/go-zero/core/validation"
  9. "github.com/zeromicro/go-zero/rest/internal/encoding"
  10. "github.com/zeromicro/go-zero/rest/internal/header"
  11. "github.com/zeromicro/go-zero/rest/pathvar"
  12. )
  13. const (
  14. formKey = "form"
  15. pathKey = "path"
  16. maxMemory = 32 << 20 // 32MB
  17. maxBodyLen = 8 << 20 // 8MB
  18. separator = ";"
  19. tokensInAttribute = 2
  20. )
  21. var (
  22. formUnmarshaler = mapping.NewUnmarshaler(formKey, mapping.WithStringValues())
  23. pathUnmarshaler = mapping.NewUnmarshaler(pathKey, mapping.WithStringValues())
  24. validator atomic.Value
  25. )
  26. // Validator defines the interface for validating the request.
  27. type Validator interface {
  28. // Validate validates the request and parsed data.
  29. Validate(r *http.Request, data any) error
  30. }
  31. // Parse parses the request.
  32. func Parse(r *http.Request, v any) error {
  33. if err := ParsePath(r, v); err != nil {
  34. return err
  35. }
  36. if err := ParseForm(r, v); err != nil {
  37. return err
  38. }
  39. if err := ParseHeaders(r, v); err != nil {
  40. return err
  41. }
  42. if err := ParseJsonBody(r, v); err != nil {
  43. return err
  44. }
  45. if valid, ok := v.(validation.Validator); ok {
  46. return valid.Validate()
  47. } else if val := validator.Load(); val != nil {
  48. return val.(Validator).Validate(r, v)
  49. }
  50. return nil
  51. }
  52. // ParseHeaders parses the headers request.
  53. func ParseHeaders(r *http.Request, v any) error {
  54. return encoding.ParseHeaders(r.Header, v)
  55. }
  56. // ParseForm parses the form request.
  57. func ParseForm(r *http.Request, v any) error {
  58. params, err := GetFormValues(r)
  59. if err != nil {
  60. return err
  61. }
  62. return formUnmarshaler.Unmarshal(params, v)
  63. }
  64. // ParseHeader parses the request header and returns a map.
  65. func ParseHeader(headerValue string) map[string]string {
  66. ret := make(map[string]string)
  67. fields := strings.Split(headerValue, separator)
  68. for _, field := range fields {
  69. field = strings.TrimSpace(field)
  70. if len(field) == 0 {
  71. continue
  72. }
  73. kv := strings.SplitN(field, "=", tokensInAttribute)
  74. if len(kv) != tokensInAttribute {
  75. continue
  76. }
  77. ret[kv[0]] = kv[1]
  78. }
  79. return ret
  80. }
  81. // ParseJsonBody parses the post request which contains json in body.
  82. func ParseJsonBody(r *http.Request, v any) error {
  83. if withJsonBody(r) {
  84. reader := io.LimitReader(r.Body, maxBodyLen)
  85. return mapping.UnmarshalJsonReader(reader, v)
  86. }
  87. return mapping.UnmarshalJsonMap(nil, v)
  88. }
  89. // ParsePath parses the symbols reside in url path.
  90. // Like http://localhost/bag/:name
  91. func ParsePath(r *http.Request, v any) error {
  92. vars := pathvar.Vars(r)
  93. m := make(map[string]any, len(vars))
  94. for k, v := range vars {
  95. m[k] = v
  96. }
  97. return pathUnmarshaler.Unmarshal(m, v)
  98. }
  99. // SetValidator sets the validator.
  100. // The validator is used to validate the request, only called in Parse,
  101. // not in ParseHeaders, ParseForm, ParseHeader, ParseJsonBody, ParsePath.
  102. func SetValidator(val Validator) {
  103. validator.Store(val)
  104. }
  105. func withJsonBody(r *http.Request) bool {
  106. return r.ContentLength > 0 && strings.Contains(r.Header.Get(header.ContentType), header.ApplicationJson)
  107. }