| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- package myth
- import (
- "bytes"
- "compress/gzip"
- "crypto/tls"
- "crypto/x509"
- "encoding/json"
- "encoding/xml"
- "errors"
- "io"
- "net"
- "net/http"
- "time"
- )
- const (
- // ReqContentTypeURL application/x-www-form-urlencoded
- ReqContentTypeURL = `application/x-www-form-urlencoded; charset=utf-8`
- // ReqContentTypeJSON application/json
- ReqContentTypeJSON = `application/json; charset=utf-8`
- // ReqContentTypeXML application/xml
- ReqContentTypeXML = `application/xml; charset=utf-8`
- // ReqContentTypeMultipart multipart/form-data
- ReqContentTypeMultipart = `multipart/form-data`
- // HTTP header Accept
- Accept = `Accept`
- // HTTP header Accept-Encoding
- AcceptEncoding = `Accept-Encoding`
- // HTTP header Content-Type
- ContentType = `Content-Type`
- // Default Accept-Encoding
- DefaultAcceptEncoding = `gzip, deflate, br`
- // ContentTypeJSON application/json
- ContentTypeJSON = `application/json; charset=utf-8`
- // ContentTypeURL application/x-www-form-urlencoded
- ContentTypeURL = `application/x-www-form-urlencoded; charset=utf-8`
- // ContentTypeURL application/xml
- ContentTypeXML = `application/xml; charset=utf-8`
- // RequestTimeOut http request timeout (second)
- RequestTimeOut = 30
- )
- const (
- // response header Content-Encoding
- ResContentEncoding = `Content-Encoding`
- // encoding gzip
- EncodingGZIP = `gzip`
- )
- var (
- reqTimeOut = time.Duration(RequestTimeOut)
- ErrStausCodeNotOk = errors.New(`StatusCode not 200`)
- )
- // GetRealIP get real IP from Request
- func GetRealIP(req *http.Request) (ip string) {
- if ips := req.Header["X-Real-Ip"]; ips != nil {
- ip = ips[0]
- }
- return
- }
- // SetHTTPRequestTimeout set request timeout
- func SetHTTPRequestTimeout(seconds int) {
- reqTimeOut = time.Duration(seconds)
- }
- // HTTPHeader HTTP header
- type HTTPHeader struct {
- header map[string]string
- }
- // DefaultTTPHeader default HTTP header
- var DefaultTTPHeader = NewDefaultHTTPHeader()
- // NewHTTPHeader new HTTPHeader
- func NewHTTPHeader() (h *HTTPHeader) {
- return &HTTPHeader{header: map[string]string{}}
- }
- // NewDefaultHTTPHeader new HTTPHeader
- func NewDefaultHTTPHeader() (h *HTTPHeader) {
- h = NewHTTPHeader()
- //h.Add(ContentType, ContentTypeJSON)
- h.Add(AcceptEncoding, DefaultAcceptEncoding)
- return
- }
- // Headers return header
- func (h *HTTPHeader) Headers() map[string]string {
- return h.header
- }
- // Add add new k-v
- func (h *HTTPHeader) Add(k, v string) {
- h.header[k] = v
- }
- // Del del k
- func (h *HTTPHeader) Del(k string) {
- delete(h.header, k)
- }
- // SetContentType set Content-Type
- func (h *HTTPHeader) SetContentType(v string) {
- h.header[ContentType] = v
- }
- // SetContentTypeJSON set Content-Type application/json
- func (h *HTTPHeader) SetContentTypeJSON() {
- h.header[ContentType] = ContentTypeJSON
- }
- // SetContentTypeURL set Content-Type application/x-www-form-urlencoded
- func (h *HTTPHeader) SetContentTypeURL() {
- h.header[ContentType] = ContentTypeURL
- }
- // SetContentTypeXML set Content-Type application/xml
- func (h *HTTPHeader) SetContentTypeXML() {
- h.header[ContentType] = ContentTypeXML
- }
- // HTTPReqOption request option
- type HTTPReqOption struct {
- }
- // HTTPMessage HTTP response
- type HTTPMessage struct {
- StatusCode int
- Body []byte
- Header http.Header
- Req *http.Request
- Res *http.Response
- }
- // Headerx return response http.Header
- func (m HTTPMessage) Headerx() http.Header {
- return m.Header
- }
- // Request return raw *http.Request
- func (m HTTPMessage) Request() *http.Request {
- return m.Req
- }
- // Response return raw *http.Response
- func (m HTTPMessage) Response() *http.Response {
- return m.Res
- }
- // ResponseBytes return Response bytes
- func (m HTTPMessage) ResponseBytes() []byte {
- return m.Body
- }
- // JSON Body to JSON
- func (m HTTPMessage) JSON(dest interface{}) (err error) {
- if m.StatusCode != http.StatusOK {
- err = ErrStausCodeNotOk
- return
- }
- err = json.Unmarshal(m.Body, &dest)
- return
- }
- // XML Body to XML
- func (m HTTPMessage) XML(dest interface{}) (err error) {
- if m.StatusCode != http.StatusOK {
- err = ErrStausCodeNotOk
- return
- }
- err = xml.Unmarshal(m.Body, &dest)
- return
- }
- // JSONQuery Body to JSONQuery
- func (m HTTPMessage) JSONQuery() (jq *JSONQuery, err error) {
- if m.StatusCode != http.StatusOK {
- err = ErrStausCodeNotOk
- return
- }
- jq, err = NewJSONQuery(m.Body)
- return
- }
- func newRequest(method, uri, certPath, keyPath string, header map[string]string, body io.Reader) (req *http.Request, res *http.Response, err error) {
- t := &http.Transport{
- Dial: func(netw, addr string) (net.Conn, error) {
- var c net.Conn
- c, err = net.DialTimeout(netw, addr, time.Second*RequestTimeOut)
- if err != nil {
- return nil, err
- }
- c.SetDeadline(time.Now().Add(time.Second * reqTimeOut))
- return c, nil
- },
- MaxIdleConnsPerHost: 50,
- ResponseHeaderTimeout: time.Second * reqTimeOut,
- }
- if certPath != "" {
- cert, e := tls.LoadX509KeyPair(certPath, keyPath)
- if e != nil {
- t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
- } else {
- pool := x509.NewCertPool()
- t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true, Certificates: []tls.Certificate{cert}, RootCAs: pool}
- }
- }
- req, err = http.NewRequest(method, uri, body)
- if err != nil {
- return
- }
- for k := range header {
- req.Header.Add(k, header[k])
- }
- client := &http.Client{Transport: t}
- res, err = client.Do(req)
- return
- }
- func readBody(msg *HTTPMessage, res *http.Response) (err error) {
- var (
- body []byte
- reader io.Reader
- )
- encoding := res.Header.Get(ResContentEncoding)
- switch encoding {
- case EncodingGZIP:
- reader, err = gzip.NewReader(res.Body)
- if err == nil {
- body, err = io.ReadAll(reader)
- }
- default:
- body, err = io.ReadAll(res.Body)
- }
- if err != nil {
- return
- }
- msg.StatusCode = res.StatusCode
- msg.Header = res.Header
- msg.Body = body
- return
- }
- // Postx request with Content-Type
- func Postx(contentType, uri string, headers map[string]string, data []byte) (msg HTTPMessage, err error) {
- headers[ContentType] = contentType
- if msg.Req, msg.Res, err = newRequest(http.MethodPost, uri, ``, ``, headers, bytes.NewReader(data)); err != nil {
- return
- }
- defer msg.Res.Body.Close()
- err = readBody(&msg, msg.Res)
- return
- }
- // Post HTTP request POST
- func Post(uri, certPath, keyPath string, header map[string]string, data io.Reader) (msg HTTPMessage, err error) {
- if msg.Req, msg.Res, err = newRequest(http.MethodPost, uri, certPath, keyPath, header, data); err != nil {
- return
- }
- defer msg.Res.Body.Close()
- err = readBody(&msg, msg.Res)
- return
- }
- // Get HTTP request GET
- func Get(uri, certPath, keyPath string, header map[string]string) (msg HTTPMessage, err error) {
- //var res *http.Response
- if msg.Req, msg.Res, err = newRequest(http.MethodGet, uri, certPath, keyPath, header, nil); err != nil {
- return
- }
- defer msg.Res.Body.Close()
- err = readBody(&msg, msg.Res)
- return
- }
|