request.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. package request
  2. import (
  3. "bytes"
  4. "crypto/tls"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "mime/multipart"
  10. "net/http"
  11. "net/url"
  12. "os"
  13. "reflect"
  14. "strings"
  15. "time"
  16. )
  17. type Request struct {
  18. cli *http.Client
  19. transport *http.Transport
  20. debug bool
  21. url string
  22. method string
  23. time int64
  24. timeout time.Duration
  25. headers map[string]string
  26. cookies map[string]string
  27. username string
  28. password string
  29. data interface{}
  30. disableKeepAlives bool
  31. tlsClientConfig *tls.Config
  32. jar http.CookieJar
  33. proxy func(*http.Request) (*url.URL, error)
  34. checkRedirect func(req *http.Request, via []*http.Request) error
  35. }
  36. func (r *Request) DisableKeepAlives(v bool) *Request {
  37. r.disableKeepAlives = v
  38. return r
  39. }
  40. func (r *Request) Jar(v http.CookieJar) *Request {
  41. r.jar = v
  42. return r
  43. }
  44. func (r *Request) CheckRedirect(v func(req *http.Request, via []*http.Request) error) *Request {
  45. r.checkRedirect = v
  46. return r
  47. }
  48. func (r *Request) TLSClient(v *tls.Config) *Request {
  49. return r.SetTLSClient(v)
  50. }
  51. func (r *Request) SetTLSClient(v *tls.Config) *Request {
  52. r.tlsClientConfig = v
  53. return r
  54. }
  55. func (r *Request) Proxy(v func(*http.Request) (*url.URL, error)) *Request {
  56. r.proxy = v
  57. return r
  58. }
  59. func (r *Request) Transport(v *http.Transport) *Request {
  60. r.transport = v
  61. return r
  62. }
  63. // Debug model
  64. func (r *Request) Debug(v bool) *Request {
  65. r.debug = v
  66. return r
  67. }
  68. // Get transport
  69. func (r *Request) getTransport() http.RoundTripper {
  70. if r.transport == nil {
  71. return http.DefaultTransport
  72. }
  73. r.transport.DisableKeepAlives = r.disableKeepAlives
  74. if r.tlsClientConfig != nil {
  75. r.transport.TLSClientConfig = r.tlsClientConfig
  76. }
  77. if r.proxy != nil {
  78. r.transport.Proxy = r.proxy
  79. }
  80. return http.RoundTripper(r.transport)
  81. }
  82. // Build client
  83. func (r *Request) buildClient() *http.Client {
  84. if r.cli == nil {
  85. r.cli = &http.Client{
  86. Transport: r.getTransport(),
  87. Jar: r.jar,
  88. CheckRedirect: r.checkRedirect,
  89. Timeout: time.Second * r.timeout,
  90. }
  91. }
  92. return r.cli
  93. }
  94. // Set headers
  95. func (r *Request) SetHeaders(headers map[string]string) *Request {
  96. if headers != nil || len(headers) > 0 {
  97. for k, v := range headers {
  98. r.headers[k] = v
  99. }
  100. }
  101. return r
  102. }
  103. // Init headers
  104. func (r *Request) initHeaders(req *http.Request) {
  105. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  106. for k, v := range r.headers {
  107. req.Header.Set(k, v)
  108. }
  109. }
  110. // Set cookies
  111. func (r *Request) SetCookies(cookies map[string]string) *Request {
  112. if cookies != nil || len(cookies) > 0 {
  113. for k, v := range cookies {
  114. r.cookies[k] = v
  115. }
  116. }
  117. return r
  118. }
  119. // Init cookies
  120. func (r *Request) initCookies(req *http.Request) {
  121. for k, v := range r.cookies {
  122. req.AddCookie(&http.Cookie{
  123. Name: k,
  124. Value: v,
  125. })
  126. }
  127. }
  128. // Set basic auth
  129. func (r *Request) SetBasicAuth(username, password string) *Request {
  130. r.username = username
  131. r.password = password
  132. return r
  133. }
  134. func (r *Request) initBasicAuth(req *http.Request) {
  135. if r.username != "" && r.password != "" {
  136. req.SetBasicAuth(r.username, r.password)
  137. }
  138. }
  139. // Check application/json
  140. func (r *Request) isJson() bool {
  141. if len(r.headers) > 0 {
  142. for _, v := range r.headers {
  143. if strings.Contains(strings.ToLower(v), "application/json") {
  144. return true
  145. }
  146. }
  147. }
  148. return false
  149. }
  150. func (r *Request) JSON() *Request {
  151. r.SetHeaders(map[string]string{"Content-Type": "application/json"})
  152. return r
  153. }
  154. // Build query data
  155. func (r *Request) buildBody(d ...interface{}) (io.Reader, error) {
  156. if r.method == "GET" || r.method == "DELETE" || len(d) == 0 || (len(d) > 0 && d[0] == nil) {
  157. return nil, nil
  158. }
  159. switch d[0].(type) {
  160. case string:
  161. return strings.NewReader(d[0].(string)), nil
  162. case []byte:
  163. return bytes.NewReader(d[0].([]byte)), nil
  164. case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
  165. return bytes.NewReader(IntByte(d[0])), nil
  166. case *bytes.Reader:
  167. return d[0].(*bytes.Reader), nil
  168. case *strings.Reader:
  169. return d[0].(*strings.Reader), nil
  170. case *bytes.Buffer:
  171. return d[0].(*bytes.Buffer), nil
  172. default:
  173. if r.isJson() {
  174. b, err := json.Marshal(d[0])
  175. if err != nil {
  176. return nil, err
  177. }
  178. return bytes.NewReader(b), nil
  179. }
  180. }
  181. t := reflect.TypeOf(d[0]).String()
  182. if !strings.Contains(t, "map[string]interface") {
  183. return nil, errors.New("Unsupported data type.")
  184. }
  185. data := make([]string, 0)
  186. for k, v := range d[0].(map[string]interface{}) {
  187. if s, ok := v.(string); ok {
  188. data = append(data, fmt.Sprintf("%s=%v", k, s))
  189. continue
  190. }
  191. b, err := json.Marshal(v)
  192. if err != nil {
  193. return nil, err
  194. }
  195. data = append(data, fmt.Sprintf("%s=%s", k, string(b)))
  196. }
  197. return strings.NewReader(strings.Join(data, "&")), nil
  198. }
  199. func (r *Request) SetTimeout(d time.Duration) *Request {
  200. r.timeout = d
  201. return r
  202. }
  203. // Parse query for GET request
  204. func parseQuery(url string) ([]string, error) {
  205. urlList := strings.Split(url, "?")
  206. if len(urlList) < 2 {
  207. return make([]string, 0), nil
  208. }
  209. query := make([]string, 0)
  210. for _, val := range strings.Split(urlList[1], "&") {
  211. v := strings.Split(val, "=")
  212. if len(v) < 2 {
  213. return make([]string, 0), errors.New("query parameter error")
  214. }
  215. query = append(query, fmt.Sprintf("%s=%s", v[0], v[1]))
  216. }
  217. return query, nil
  218. }
  219. // Build GET request url
  220. func buildUrl(url string, data ...interface{}) (string, error) {
  221. query, err := parseQuery(url)
  222. if err != nil {
  223. return url, err
  224. }
  225. if len(data) > 0 && data[0] != nil {
  226. t := reflect.TypeOf(data[0]).String()
  227. switch t {
  228. case "map[string]interface {}":
  229. for k, v := range data[0].(map[string]interface{}) {
  230. vv := ""
  231. if reflect.TypeOf(v).String() == "string" {
  232. vv = v.(string)
  233. } else {
  234. b, err := json.Marshal(v)
  235. if err != nil {
  236. return url, err
  237. }
  238. vv = string(b)
  239. }
  240. query = append(query, fmt.Sprintf("%s=%s", k, vv))
  241. }
  242. case "string":
  243. param := data[0].(string)
  244. if param != "" {
  245. query = append(query, param)
  246. }
  247. default:
  248. return url, errors.New("Unsupported data type.")
  249. }
  250. }
  251. list := strings.Split(url, "?")
  252. if len(query) > 0 {
  253. return fmt.Sprintf("%s?%s", list[0], strings.Join(query, "&")), nil
  254. }
  255. return list[0], nil
  256. }
  257. func (r *Request) elapsedTime(n int64, resp *Response) {
  258. end := time.Now().UnixNano() / 1e6
  259. resp.time = end - n
  260. }
  261. func (r *Request) log() {
  262. if r.debug {
  263. fmt.Printf("[HttpUtils]\n")
  264. fmt.Printf("-------------------------------------------------------------------\n")
  265. fmt.Printf("Request: %s %s\nHeaders: %v\nCookies: %v\nTimeout: %ds\nReqBody: %v\n\n", r.method, r.url, r.headers, r.cookies, r.timeout, r.data)
  266. //fmt.Printf("-------------------------------------------------------------------\n\n")
  267. }
  268. }
  269. // get is a get http request
  270. func (r *Request) get(url string, data ...interface{}) (*Response, error) {
  271. return r.request(http.MethodGet, url, data...)
  272. }
  273. // post is a post http request
  274. func (r *Request) post(url string, data ...interface{}) (*Response, error) {
  275. return r.request(http.MethodPost, url, data...)
  276. }
  277. // put is a put http request
  278. func (r *Request) put(url string, data ...interface{}) (*Response, error) {
  279. return r.request(http.MethodPut, url, data...)
  280. }
  281. // delete is a delete http request
  282. func (r *Request) delete(url string, data ...interface{}) (*Response, error) {
  283. return r.request(http.MethodDelete, url, data...)
  284. }
  285. // Upload file
  286. func (r *Request) upload(url, filename, fileinput string) (*Response, error) {
  287. return r.sendFile(url, filename, fileinput)
  288. }
  289. // Get is a get http request
  290. func (r *Request) Get(url string, data ...interface{}) (string, error) {
  291. request, err := r.request(http.MethodGet, strings.TrimSpace(url), data...)
  292. if err != nil {
  293. return "", err
  294. }
  295. body, err := request.Body()
  296. if err != nil {
  297. return "", err
  298. }
  299. s := string(body)
  300. return s, nil
  301. }
  302. // Post is a post http request
  303. func (r *Request) Post(url string, data ...interface{}) (string, error) {
  304. request, err := r.request(http.MethodPost, strings.TrimSpace(url), data...)
  305. if err != nil {
  306. return "", err
  307. }
  308. body, err := request.Body()
  309. if err != nil {
  310. return "", err
  311. }
  312. s := string(body)
  313. return s, nil
  314. }
  315. // Put is a put http request
  316. func (r *Request) Put(url string, data ...interface{}) (string, error) {
  317. request, err := r.request(http.MethodPut, strings.TrimSpace(url), data...)
  318. if err != nil {
  319. return "", err
  320. }
  321. body, err := request.Body()
  322. if err != nil {
  323. return "", err
  324. }
  325. s := string(body)
  326. return s, nil
  327. }
  328. // Delete is a delete http request
  329. func (r *Request) Delete(url string, data ...interface{}) (string, error) {
  330. request, err := r.request(http.MethodDelete, strings.TrimSpace(url), data...)
  331. if err != nil {
  332. return "", err
  333. }
  334. body, err := request.Body()
  335. if err != nil {
  336. return "", err
  337. }
  338. s := string(body)
  339. return s, nil
  340. }
  341. // Upload file
  342. func (r *Request) Upload(url, filename, fileinput string) (string, error) {
  343. file, err := r.sendFile(strings.TrimSpace(url), filename, fileinput)
  344. if err != nil {
  345. return "", err
  346. }
  347. body, err := file.Body()
  348. if err != nil {
  349. return "", err
  350. }
  351. s := string(body)
  352. return s, nil
  353. }
  354. // Send http request
  355. func (r *Request) request(method, url string, data ...interface{}) (*Response, error) {
  356. // Build Response
  357. response := &Response{}
  358. // Start time
  359. start := time.Now().UnixNano() / 1e6
  360. // Count elapsed time
  361. defer r.elapsedTime(start, response)
  362. if method == "" || url == "" {
  363. return nil, errors.New("parameter method and url is required")
  364. }
  365. // Debug infomation
  366. defer r.log()
  367. r.url = url
  368. if len(data) > 0 {
  369. r.data = data[0]
  370. } else {
  371. r.data = ""
  372. }
  373. var (
  374. err error
  375. req *http.Request
  376. body io.Reader
  377. )
  378. r.cli = r.buildClient()
  379. method = strings.ToUpper(method)
  380. r.method = method
  381. if method == "GET" || method == "DELETE" {
  382. url, err = buildUrl(url, data...)
  383. if err != nil {
  384. return nil, err
  385. }
  386. r.url = url
  387. }
  388. body, err = r.buildBody(data...)
  389. if err != nil {
  390. return nil, err
  391. }
  392. req, err = http.NewRequest(method, url, body)
  393. if err != nil {
  394. return nil, err
  395. }
  396. r.initHeaders(req)
  397. r.initCookies(req)
  398. r.initBasicAuth(req)
  399. resp, err := r.cli.Do(req)
  400. if err != nil {
  401. return nil, err
  402. }
  403. response.url = url
  404. response.resp = resp
  405. return response, nil
  406. }
  407. // Send file
  408. func (r *Request) sendFile(url, filename, fileinput string) (*Response, error) {
  409. if url == "" {
  410. return nil, errors.New("parameter url is required")
  411. }
  412. fileBuffer := &bytes.Buffer{}
  413. bodyWriter := multipart.NewWriter(fileBuffer)
  414. fileWriter, er := bodyWriter.CreateFormFile(fileinput, filename)
  415. if er != nil {
  416. return nil, er
  417. }
  418. f, er := os.Open(filename)
  419. if er != nil {
  420. return nil, er
  421. }
  422. defer f.Close()
  423. _, er = io.Copy(fileWriter, f)
  424. if er != nil {
  425. return nil, er
  426. }
  427. contentType := bodyWriter.FormDataContentType()
  428. bodyWriter.Close()
  429. // Build Response
  430. response := &Response{}
  431. // Start time
  432. start := time.Now().UnixNano() / 1e6
  433. // Count elapsed time
  434. defer r.elapsedTime(start, response)
  435. // Debug infomation
  436. defer r.log()
  437. r.url = url
  438. r.data = nil
  439. var (
  440. err error
  441. req *http.Request
  442. )
  443. r.cli = r.buildClient()
  444. r.method = "POST"
  445. req, err = http.NewRequest(r.method, url, fileBuffer)
  446. if err != nil {
  447. return nil, err
  448. }
  449. r.initHeaders(req)
  450. r.initCookies(req)
  451. r.initBasicAuth(req)
  452. req.Header.Set("Content-Type", contentType)
  453. resp, err := r.cli.Do(req)
  454. if err != nil {
  455. return nil, err
  456. }
  457. response.url = url
  458. response.resp = resp
  459. return response, nil
  460. }