request.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. package myth
  2. import (
  3. "compress/gzip"
  4. "crypto/tls"
  5. "crypto/x509"
  6. "encoding/json"
  7. "encoding/xml"
  8. "errors"
  9. "io"
  10. "net"
  11. "net/http"
  12. "time"
  13. )
  14. const (
  15. // ReqContentTypeURL application/x-www-form-urlencoded
  16. ReqContentTypeURL = `application/x-www-form-urlencoded; charset=utf-8`
  17. // ReqContentTypeJSON application/json
  18. ReqContentTypeJSON = `application/json; charset=utf-8`
  19. // ReqContentTypeXML application/xml
  20. ReqContentTypeXML = `application/xml; charset=utf-8`
  21. // ReqContentTypeMultipart multipart/form-data
  22. ReqContentTypeMultipart = `multipart/form-data`
  23. // HTTP header Accept-Encoding
  24. AcceptEncoding = `Accept-Encoding`
  25. // HTTP header Content-Type
  26. ContentType = `Content-Type`
  27. // Default Accept-Encoding
  28. DefaultAcceptEncoding = `gzip, deflate, br`
  29. // ContentTypeJSON application/json
  30. ContentTypeJSON = `application/json; charset=utf-8`
  31. // RequestTimeOut http request timeout (second)
  32. RequestTimeOut = 30
  33. )
  34. const (
  35. // response header Content-Encoding
  36. ResContentEncoding = `Content-Encoding`
  37. // encoding gzip
  38. EncodingGZIP = `gzip`
  39. )
  40. var (
  41. reqTimeOut = time.Duration(RequestTimeOut)
  42. ErrStausCodeNotOk = errors.New(`StatusCode not 200`)
  43. )
  44. // GetRealIP get real IP from Request
  45. func GetRealIP(req *http.Request) (ip string) {
  46. if ips := req.Header["X-Real-Ip"]; ips != nil {
  47. ip = ips[0]
  48. }
  49. return
  50. }
  51. // SetHTTPRequestTimeout set request timeout
  52. func SetHTTPRequestTimeout(seconds int) {
  53. reqTimeOut = time.Duration(seconds)
  54. }
  55. // HTTPHeader HTTP header
  56. type HTTPHeader struct {
  57. header map[string]string
  58. }
  59. // DefaultTTPHeader default HTTP header
  60. var DefaultTTPHeader = NewDefaultHTTPHeader()
  61. // NewHTTPHeader new HTTPHeader
  62. func NewHTTPHeader() (h *HTTPHeader) {
  63. return &HTTPHeader{header: map[string]string{}}
  64. }
  65. // NewDefaultHTTPHeader new HTTPHeader
  66. func NewDefaultHTTPHeader() (h *HTTPHeader) {
  67. h = NewHTTPHeader()
  68. //h.Add(ContentType, ContentTypeJSON)
  69. h.Add(AcceptEncoding, DefaultAcceptEncoding)
  70. return
  71. }
  72. // Headers return header
  73. func (h *HTTPHeader) Headers() map[string]string {
  74. return h.header
  75. }
  76. // Add add new k-v
  77. func (h *HTTPHeader) Add(k, v string) {
  78. h.header[k] = v
  79. }
  80. // Del del k
  81. func (h *HTTPHeader) Del(k string) {
  82. delete(h.header, k)
  83. }
  84. // HTTPReqOption request option
  85. type HTTPReqOption struct {
  86. }
  87. // HTTPMessage HTTP response
  88. type HTTPMessage struct {
  89. StatusCode int
  90. Body []byte
  91. Header http.Header
  92. Req *http.Request
  93. Res *http.Response
  94. }
  95. // JSON Body to JSON
  96. func (m HTTPMessage) JSON(dest interface{}) (err error) {
  97. if m.StatusCode != http.StatusOK {
  98. err = ErrStausCodeNotOk
  99. return
  100. }
  101. err = json.Unmarshal(m.Body, &dest)
  102. return
  103. }
  104. // XML Body to XML
  105. func (m HTTPMessage) XML(dest interface{}) (err error) {
  106. if m.StatusCode != http.StatusOK {
  107. err = ErrStausCodeNotOk
  108. return
  109. }
  110. err = xml.Unmarshal(m.Body, &dest)
  111. return
  112. }
  113. // JSONQuery Body to JSONQuery
  114. func (m HTTPMessage) JSONQuery() (jq *JSONQuery, err error) {
  115. if m.StatusCode != http.StatusOK {
  116. err = ErrStausCodeNotOk
  117. return
  118. }
  119. jq, err = NewJSONQuery(m.Body)
  120. return
  121. }
  122. func newRequest(method, uri, certPath, keyPath string, header map[string]string, body io.Reader) (req *http.Request, res *http.Response, err error) {
  123. t := &http.Transport{
  124. Dial: func(netw, addr string) (net.Conn, error) {
  125. var c net.Conn
  126. c, err = net.DialTimeout(netw, addr, time.Second*RequestTimeOut)
  127. if err != nil {
  128. return nil, err
  129. }
  130. c.SetDeadline(time.Now().Add(time.Second * reqTimeOut))
  131. return c, nil
  132. },
  133. MaxIdleConnsPerHost: 50,
  134. ResponseHeaderTimeout: time.Second * reqTimeOut,
  135. }
  136. if certPath != "" {
  137. cert, e := tls.LoadX509KeyPair(certPath, keyPath)
  138. if e != nil {
  139. t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
  140. } else {
  141. pool := x509.NewCertPool()
  142. t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true, Certificates: []tls.Certificate{cert}, RootCAs: pool}
  143. }
  144. }
  145. var (
  146. client = &http.Client{Transport: t}
  147. )
  148. req, err = http.NewRequest(method, uri, body)
  149. if err != nil {
  150. return
  151. }
  152. for k := range header {
  153. req.Header.Add(k, header[k])
  154. }
  155. res, err = client.Do(req)
  156. return
  157. }
  158. func readBody(msg *HTTPMessage, res *http.Response) (err error) {
  159. var (
  160. body []byte
  161. reader io.Reader
  162. )
  163. encoding := res.Header.Get(ResContentEncoding)
  164. switch encoding {
  165. case EncodingGZIP:
  166. reader, err = gzip.NewReader(res.Body)
  167. if err == nil {
  168. body, err = io.ReadAll(reader)
  169. }
  170. default:
  171. body, err = io.ReadAll(res.Body)
  172. }
  173. if err != nil {
  174. return
  175. }
  176. msg.StatusCode = res.StatusCode
  177. msg.Header = res.Header
  178. msg.Body = body
  179. return
  180. }
  181. // Post HTTP request POST
  182. func Post(uri, certPath, keyPath string, header map[string]string, data io.Reader) (msg HTTPMessage, err error) {
  183. if msg.Req, msg.Res, err = newRequest(http.MethodPost, uri, certPath, keyPath, header, data); err != nil {
  184. return
  185. }
  186. defer msg.Res.Body.Close()
  187. err = readBody(&msg, msg.Res)
  188. return
  189. }
  190. // Get HTTP request GET
  191. func Get(uri, certPath, keyPath string, header map[string]string) (msg HTTPMessage, err error) {
  192. //var res *http.Response
  193. if msg.Req, msg.Res, err = newRequest(http.MethodGet, uri, certPath, keyPath, header, nil); err != nil {
  194. return
  195. }
  196. defer msg.Res.Body.Close()
  197. err = readBody(&msg, msg.Res)
  198. return
  199. }