request.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. package request
  2. import (
  3. "context"
  4. "encoding/json"
  5. "encoding/xml"
  6. "fmt"
  7. "io"
  8. "net/http"
  9. "net/url"
  10. "os"
  11. "path"
  12. "reflect"
  13. "regexp"
  14. "strings"
  15. )
  16. const (
  17. JSON = "application/json"
  18. XML = "application/xml"
  19. plainTextType = "text/plain; charset=utf-8"
  20. jsonContentType = "application/json"
  21. formContentType = "application/x-www-form-urlencoded"
  22. )
  23. var (
  24. jsonCheck = regexp.MustCompile(`(?i:(application|text)/(json|.*\+json|json\-.*)(;|$))`)
  25. xmlCheck = regexp.MustCompile(`(?i:(application|text)/(xml|.*\+xml)(;|$))`)
  26. )
  27. type Request struct {
  28. context context.Context
  29. method string
  30. uri string
  31. url *url.URL
  32. body any
  33. query url.Values
  34. formData url.Values
  35. header http.Header
  36. contentType string
  37. authorization Authorization
  38. client *Client
  39. rawRequest *http.Request
  40. rawResponse *http.Response
  41. }
  42. func (r *Request) detectContentType(body interface{}) string {
  43. contentType := plainTextType
  44. kind := reflect.Indirect(reflect.ValueOf(body)).Type().Kind()
  45. switch kind {
  46. case reflect.Struct, reflect.Map:
  47. contentType = jsonContentType
  48. case reflect.String:
  49. contentType = plainTextType
  50. default:
  51. if b, ok := body.([]byte); ok {
  52. contentType = http.DetectContentType(b)
  53. } else if kind == reflect.Slice {
  54. contentType = jsonContentType
  55. }
  56. }
  57. return contentType
  58. }
  59. func (r *Request) readRequestBody(contentType string, body any) (buf []byte, err error) {
  60. var (
  61. ok bool
  62. s string
  63. reader io.Reader
  64. )
  65. kind := reflect.Indirect(reflect.ValueOf(body)).Type().Kind()
  66. if reader, ok = r.body.(io.Reader); ok {
  67. buf, err = io.ReadAll(reader)
  68. goto __end
  69. }
  70. if buf, ok = r.body.([]byte); ok {
  71. goto __end
  72. }
  73. if s, ok = r.body.(string); ok {
  74. buf = []byte(s)
  75. goto __end
  76. }
  77. if jsonCheck.MatchString(contentType) && (kind == reflect.Struct || kind == reflect.Map || kind == reflect.Slice) {
  78. buf, err = json.Marshal(r.body)
  79. goto __end
  80. }
  81. if xmlCheck.MatchString(contentType) && (kind == reflect.Struct) {
  82. buf, err = xml.Marshal(r.body)
  83. goto __end
  84. }
  85. err = fmt.Errorf("unmarshal content type %s", contentType)
  86. __end:
  87. return
  88. }
  89. func (r *Request) SetContext(ctx context.Context) *Request {
  90. r.context = ctx
  91. return r
  92. }
  93. func (r *Request) AddQuery(k, v string) *Request {
  94. r.query.Add(k, v)
  95. return r
  96. }
  97. func (r *Request) SetQuery(vs map[string]string) *Request {
  98. for k, v := range vs {
  99. r.query.Set(k, v)
  100. }
  101. return r
  102. }
  103. func (r *Request) AddFormData(k, v string) *Request {
  104. r.contentType = formContentType
  105. r.formData.Add(k, v)
  106. return r
  107. }
  108. func (r *Request) SetFormData(vs map[string]string) *Request {
  109. r.contentType = formContentType
  110. for k, v := range vs {
  111. r.formData.Set(k, v)
  112. }
  113. return r
  114. }
  115. func (r *Request) SetBody(v any) *Request {
  116. r.body = v
  117. return r
  118. }
  119. func (r *Request) SetContentType(v string) *Request {
  120. r.contentType = v
  121. return r
  122. }
  123. func (r *Request) AddHeader(k, v string) *Request {
  124. r.header.Add(k, v)
  125. return r
  126. }
  127. func (r *Request) SetHeader(h http.Header) *Request {
  128. r.header = h
  129. return r
  130. }
  131. func (r *Request) Do() (res *http.Response, err error) {
  132. var s string
  133. s = r.formData.Encode()
  134. if len(s) > 0 {
  135. r.body = s
  136. }
  137. r.url.RawQuery = r.query.Encode()
  138. r.uri = r.url.String()
  139. return r.client.execute(r)
  140. }
  141. func (r *Request) Response(v any) (err error) {
  142. var (
  143. res *http.Response
  144. buf []byte
  145. contentType string
  146. )
  147. if res, err = r.Do(); err != nil {
  148. return
  149. }
  150. defer func() {
  151. _ = res.Body.Close()
  152. }()
  153. if res.StatusCode/100 != 2 {
  154. if buf, err = io.ReadAll(res.Body); err == nil && len(buf) > 0 {
  155. err = fmt.Errorf("http response %s(%d): %s", res.Status, res.StatusCode, string(buf))
  156. } else {
  157. err = fmt.Errorf("http response %d: %s", res.StatusCode, res.Status)
  158. }
  159. return
  160. }
  161. contentType = strings.ToLower(res.Header.Get("Content-Type"))
  162. extName := path.Ext(r.rawRequest.URL.String())
  163. if strings.Contains(contentType, JSON) || extName == ".json" {
  164. err = json.NewDecoder(res.Body).Decode(v)
  165. } else if strings.Contains(contentType, XML) || extName == ".xml" {
  166. err = xml.NewDecoder(res.Body).Decode(v)
  167. } else {
  168. err = fmt.Errorf("unsupported content type: %s", contentType)
  169. }
  170. return
  171. }
  172. func (r *Request) Download(s string) (err error) {
  173. var (
  174. fp *os.File
  175. res *http.Response
  176. )
  177. if res, err = r.Do(); err != nil {
  178. return
  179. }
  180. defer func() {
  181. _ = res.Body.Close()
  182. }()
  183. if fp, err = os.OpenFile(s, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644); err != nil {
  184. return
  185. }
  186. defer func() {
  187. _ = fp.Close()
  188. }()
  189. _, err = io.Copy(fp, res.Body)
  190. return
  191. }
  192. func newRequest(method string, uri string, client *Client) *Request {
  193. var (
  194. err error
  195. )
  196. r := &Request{
  197. context: context.Background(),
  198. method: method,
  199. uri: uri,
  200. header: make(http.Header),
  201. formData: make(url.Values),
  202. client: client,
  203. }
  204. if r.url, err = url.Parse(uri); err == nil {
  205. r.query = r.url.Query()
  206. } else {
  207. r.query = make(url.Values)
  208. }
  209. return r
  210. }