You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

http.go 7.0 kB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. package http
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "mime/multipart"
  7. "net/http"
  8. ul "net/url"
  9. "strings"
  10. "gitlink.org.cn/cloudream/common/pkgs/iterator"
  11. "gitlink.org.cn/cloudream/common/utils/math"
  12. "gitlink.org.cn/cloudream/common/utils/serder"
  13. )
  14. const (
  15. ContentTypeJSON = "application/json"
  16. ContentTypeForm = "application/x-www-form-urlencoded"
  17. ContentTypeMultiPart = "multipart/form-data"
  18. ContentTypeOctetStream = "application/octet-stream"
  19. )
  20. type RequestParam struct {
  21. Header any
  22. Query any
  23. Body any
  24. }
  25. func GetJSON(url string, param RequestParam) (*http.Response, error) {
  26. req, err := http.NewRequest(http.MethodGet, url, nil)
  27. if err != nil {
  28. return nil, err
  29. }
  30. if err = prepareQuery(req, param.Query); err != nil {
  31. return nil, err
  32. }
  33. if err = prepareHeader(req, param.Header); err != nil {
  34. return nil, err
  35. }
  36. if err = prepareJSONBody(req, param.Body); err != nil {
  37. return nil, err
  38. }
  39. return http.DefaultClient.Do(req)
  40. }
  41. func GetForm(url string, param RequestParam) (*http.Response, error) {
  42. req, err := http.NewRequest(http.MethodGet, url, nil)
  43. if err != nil {
  44. return nil, err
  45. }
  46. if err = prepareQuery(req, param.Query); err != nil {
  47. return nil, err
  48. }
  49. if err = prepareHeader(req, param.Header); err != nil {
  50. return nil, err
  51. }
  52. if err = prepareFormBody(req, param.Body); err != nil {
  53. return nil, err
  54. }
  55. return http.DefaultClient.Do(req)
  56. }
  57. func PostJSON(url string, param RequestParam) (*http.Response, error) {
  58. req, err := http.NewRequest(http.MethodPost, url, nil)
  59. if err != nil {
  60. return nil, err
  61. }
  62. if err = prepareQuery(req, param.Query); err != nil {
  63. return nil, err
  64. }
  65. if err = prepareHeader(req, param.Header); err != nil {
  66. return nil, err
  67. }
  68. if err = prepareJSONBody(req, param.Body); err != nil {
  69. return nil, err
  70. }
  71. return http.DefaultClient.Do(req)
  72. }
  73. func PostForm(url string, param RequestParam) (*http.Response, error) {
  74. req, err := http.NewRequest(http.MethodPost, url, nil)
  75. if err != nil {
  76. return nil, err
  77. }
  78. if err = prepareQuery(req, param.Query); err != nil {
  79. return nil, err
  80. }
  81. if err = prepareHeader(req, param.Header); err != nil {
  82. return nil, err
  83. }
  84. if err = prepareFormBody(req, param.Body); err != nil {
  85. return nil, err
  86. }
  87. return http.DefaultClient.Do(req)
  88. }
  89. func ParseJSONResponse[TBody any](resp *http.Response) (TBody, error) {
  90. var ret TBody
  91. contType := resp.Header.Get("Content-Type")
  92. if strings.Contains(contType, ContentTypeJSON) {
  93. if err := serder.JSONToObjectStream(resp.Body, &ret); err != nil {
  94. return ret, fmt.Errorf("parsing response: %w", err)
  95. }
  96. return ret, nil
  97. }
  98. cont, err := io.ReadAll(resp.Body)
  99. if err != nil {
  100. return ret, fmt.Errorf("unknow response content type: %s, status: %d", contType, resp.StatusCode)
  101. }
  102. strCont := string(cont)
  103. return ret, fmt.Errorf("unknow response content type: %s, status: %d, body(prefix): %s", contType, resp.StatusCode, strCont[:math.Min(len(strCont), 200)])
  104. }
  105. type MultiPartRequestParam struct {
  106. Header any
  107. Query any
  108. Form any
  109. Files MultiPartFileIterator
  110. }
  111. type MultiPartFileIterator = iterator.Iterator[*IterMultiPartFile]
  112. type IterMultiPartFile struct {
  113. FieldName string // 这个文件所属的form字段
  114. FileName string // 文件名
  115. File io.ReadCloser
  116. }
  117. func PostMultiPart(url string, param MultiPartRequestParam) (*http.Response, error) {
  118. req, err := http.NewRequest(http.MethodPost, url, nil)
  119. if err != nil {
  120. return nil, err
  121. }
  122. if err = prepareQuery(req, param.Query); err != nil {
  123. return nil, err
  124. }
  125. if err = prepareHeader(req, param.Header); err != nil {
  126. return nil, err
  127. }
  128. pr, pw := io.Pipe()
  129. muWriter := multipart.NewWriter(pw)
  130. setHeader(req.Header, "Content-Type", fmt.Sprintf("%s;boundary=%s", ContentTypeMultiPart, muWriter.Boundary()))
  131. writeResult := make(chan error, 1)
  132. go func() {
  133. writeResult <- func() error {
  134. defer pw.Close()
  135. defer muWriter.Close()
  136. if param.Form != nil {
  137. mp, err := serder.ObjectToMap(param.Form)
  138. if err != nil {
  139. return fmt.Errorf("formValues object to map failed, err: %w", err)
  140. }
  141. for k, v := range mp {
  142. err := muWriter.WriteField(k, fmt.Sprintf("%v", v))
  143. if err != nil {
  144. return fmt.Errorf("write form field failed, err: %w", err)
  145. }
  146. }
  147. }
  148. for {
  149. file, err := param.Files.MoveNext()
  150. if err == iterator.ErrNoMoreItem {
  151. break
  152. }
  153. if err != nil {
  154. return fmt.Errorf("opening file: %w", err)
  155. }
  156. err = func() error {
  157. defer file.File.Close()
  158. w, err := muWriter.CreateFormFile(file.FieldName, file.FileName)
  159. if err != nil {
  160. return fmt.Errorf("create form file failed, err: %w", err)
  161. }
  162. _, err = io.Copy(w, file.File)
  163. if err != nil {
  164. return err
  165. }
  166. return nil
  167. }()
  168. if err != nil {
  169. return err
  170. }
  171. }
  172. return nil
  173. }()
  174. }()
  175. req.Body = pr
  176. cli := http.Client{}
  177. resp, err := cli.Do(req)
  178. if err != nil {
  179. return nil, err
  180. }
  181. writeErr := <-writeResult
  182. if writeErr != nil {
  183. return nil, writeErr
  184. }
  185. return resp, nil
  186. }
  187. func prepareQuery(req *http.Request, query any) error {
  188. if query == nil {
  189. return nil
  190. }
  191. mp, ok := query.(map[string]any)
  192. if !ok {
  193. var err error
  194. if mp, err = serder.ObjectToMap(query); err != nil {
  195. return fmt.Errorf("query object to map: %w", err)
  196. }
  197. }
  198. values := make(ul.Values)
  199. for k, v := range mp {
  200. values.Add(k, fmt.Sprintf("%v", v))
  201. }
  202. req.URL.RawQuery = values.Encode()
  203. return nil
  204. }
  205. func prepareHeader(req *http.Request, header any) error {
  206. if header == nil {
  207. return nil
  208. }
  209. mp, ok := header.(map[string]any)
  210. if !ok {
  211. var err error
  212. if mp, err = serder.ObjectToMap(header); err != nil {
  213. return fmt.Errorf("header object to map: %w", err)
  214. }
  215. }
  216. req.Header = make(http.Header)
  217. for k, v := range mp {
  218. req.Header.Set(k, fmt.Sprintf("%v", v))
  219. }
  220. return nil
  221. }
  222. func prepareJSONBody(req *http.Request, body any) error {
  223. setHeader(req.Header, "Content-Type", ContentTypeJSON)
  224. if body == nil {
  225. return nil
  226. }
  227. data, err := serder.ObjectToJSON(body)
  228. if err != nil {
  229. return err
  230. }
  231. req.ContentLength = int64(len(data))
  232. req.Body = io.NopCloser(bytes.NewReader(data))
  233. return nil
  234. }
  235. func prepareFormBody(req *http.Request, body any) error {
  236. setHeader(req.Header, "Content-Type", ContentTypeForm)
  237. if body == nil {
  238. return nil
  239. }
  240. mp, ok := body.(map[string]any)
  241. if !ok {
  242. var err error
  243. if mp, err = serder.ObjectToMap(body); err != nil {
  244. return fmt.Errorf("body object to map: %w", err)
  245. }
  246. }
  247. values := make(ul.Values)
  248. for k, v := range mp {
  249. values.Add(k, fmt.Sprintf("%v", v))
  250. }
  251. data := values.Encode()
  252. req.Body = io.NopCloser(strings.NewReader(data))
  253. req.ContentLength = int64(len(data))
  254. return nil
  255. }
  256. func setHeader(mp http.Header, key, value string) http.Header {
  257. if mp == nil {
  258. mp = make(http.Header)
  259. }
  260. mp.Set(key, value)
  261. return mp
  262. }
  263. func setValue(values ul.Values, key, value string) ul.Values {
  264. if values == nil {
  265. values = make(ul.Values)
  266. }
  267. values.Add(key, value)
  268. return values
  269. }