package htp import ( "bytes" "io/ioutil" "net/http" "one.com/kettle/utl" "time" ) type ClientOption func(*Client) func WithUserAgent(ua string) ClientOption { return func(c *Client){ c.ua = ua } } type Client struct { c *http.Client req *http.Request ua string } func NewClient(options ...ClientOption) *Client { c := &http.Client{ Transport: &http.Transport{ TLSHandshakeTimeout: 3 * time.Second, MaxIdleConnsPerHost: 20, MaxIdleConns: 20, IdleConnTimeout: 90 * time.Second, }, Timeout: 3 * time.Second, } clt := &Client{ c: c, } for _, opt := range options { opt(clt) } return clt } func (self *Client) Get(url string) ([]byte, error) { return self.request(http.MethodGet, url, nil, nil) } func (self *Client) Post(url string, headers map[string]string, body []byte) ([]byte, error) { return self.request(http.MethodPost, url, headers, body) } func (self *Client) request(method, url string, headers map[string]string, body []byte) ([]byte, error) { params := bytes.NewReader(body) req, err := http.NewRequest(method, url, params) if err != nil { return nil, err } if len(self.ua) > 0 { req.Header.Set("User-Agent", self.ua) } for k, v := range headers { req.Header.Add(k, v) } resp, err := self.c.Do(req) if err != nil { return nil, err } if resp.StatusCode != http.StatusOK { // sometime StatusCode <> 200 may not represents an error return nil, utl.ErrForCode(resp.StatusCode) } if resp == nil { return nil, utl.ErrContainerEmpty } defer resp.Body.Close() return ioutil.ReadAll(resp.Body) } /////////////////////// chaining call