requests.go 2.9 KB

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