request.go 4.9 KB

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