requests.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. package httpx
  2. import (
  3. "io"
  4. "net/http"
  5. "strings"
  6. "github.com/tal-tech/go-zero/core/mapping"
  7. "github.com/tal-tech/go-zero/rest/internal/context"
  8. )
  9. const (
  10. multipartFormData = "multipart/form-data"
  11. formKey = "form"
  12. pathKey = "path"
  13. emptyJson = "{}"
  14. maxMemory = 32 << 20 // 32MB
  15. maxBodyLen = 8 << 20 // 8MB
  16. separator = ";"
  17. tokensInAttribute = 2
  18. )
  19. var (
  20. formUnmarshaler = mapping.NewUnmarshaler(formKey, mapping.WithStringValues())
  21. pathUnmarshaler = mapping.NewUnmarshaler(pathKey, mapping.WithStringValues())
  22. )
  23. func Parse(r *http.Request, v interface{}) error {
  24. if err := ParsePath(r, v); err != nil {
  25. return err
  26. }
  27. if err := ParseForm(r, v); err != nil {
  28. return err
  29. }
  30. return ParseJsonBody(r, v)
  31. }
  32. // Parses the form request.
  33. func ParseForm(r *http.Request, v interface{}) error {
  34. if strings.Contains(r.Header.Get(ContentType), multipartFormData) {
  35. if err := r.ParseMultipartForm(maxMemory); err != nil {
  36. return err
  37. }
  38. } else {
  39. if err := r.ParseForm(); err != nil {
  40. return err
  41. }
  42. }
  43. params := make(map[string]interface{}, len(r.Form))
  44. for name := range r.Form {
  45. formValue := r.Form.Get(name)
  46. if len(formValue) > 0 {
  47. params[name] = formValue
  48. }
  49. }
  50. return formUnmarshaler.Unmarshal(params, v)
  51. }
  52. func ParseHeader(headerValue string) map[string]string {
  53. ret := make(map[string]string)
  54. fields := strings.Split(headerValue, separator)
  55. for _, field := range fields {
  56. field = strings.TrimSpace(field)
  57. if len(field) == 0 {
  58. continue
  59. }
  60. kv := strings.SplitN(field, "=", tokensInAttribute)
  61. if len(kv) != tokensInAttribute {
  62. continue
  63. }
  64. ret[kv[0]] = kv[1]
  65. }
  66. return ret
  67. }
  68. // Parses the post request which contains json in body.
  69. func ParseJsonBody(r *http.Request, v interface{}) error {
  70. var reader io.Reader
  71. if withJsonBody(r) {
  72. reader = io.LimitReader(r.Body, maxBodyLen)
  73. } else {
  74. reader = strings.NewReader(emptyJson)
  75. }
  76. return mapping.UnmarshalJsonReader(reader, v)
  77. }
  78. // Parses the symbols reside in url path.
  79. // Like http://localhost/bag/:name
  80. func ParsePath(r *http.Request, v interface{}) error {
  81. vars := context.Vars(r)
  82. m := make(map[string]interface{}, len(vars))
  83. for k, v := range vars {
  84. m[k] = v
  85. }
  86. return pathUnmarshaler.Unmarshal(m, v)
  87. }
  88. func withJsonBody(r *http.Request) bool {
  89. return r.ContentLength > 0 && strings.Contains(r.Header.Get(ContentType), ApplicationJson)
  90. }