request.go 6.6 KB

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