package request import ( "crypto/tls" "io" "net" "net/http" "net/http/cookiejar" "strings" "time" ) type ( BeforeRequest func(req *http.Request) (err error) AfterRequest func(req *http.Request, res *http.Response) (err error) Client struct { baseUrl string Authorization Authorization client *http.Client cookieJar *cookiejar.Jar interceptorRequest []BeforeRequest interceptorResponse []AfterRequest } ) var ( DefaultClient = &http.Client{ Transport: &http.Transport{ Proxy: http.ProxyFromEnvironment, ForceAttemptHTTP2: true, MaxIdleConns: 64, MaxIdleConnsPerHost: 8, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, }, Timeout: time.Second * 30, } UnsafeClient = &http.Client{ Transport: &http.Transport{ Proxy: http.ProxyFromEnvironment, ForceAttemptHTTP2: true, DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }).DialContext, MaxIdleConns: 64, MaxIdleConnsPerHost: 8, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, }, Timeout: time.Second * 30, } ) func (client *Client) stashUri(urlPath string) string { var ( pos int ) if len(urlPath) == 0 { return client.baseUrl } if pos = strings.Index(urlPath, "//"); pos == -1 { if client.baseUrl != "" { if urlPath[0] != '/' { urlPath = "/" + urlPath } return client.baseUrl + urlPath } } return urlPath } func (client *Client) BeforeRequest(cb BeforeRequest) *Client { client.interceptorRequest = append(client.interceptorRequest, cb) return client } func (client *Client) AfterRequest(cb AfterRequest) *Client { client.interceptorResponse = append(client.interceptorResponse, cb) return client } func (client *Client) SetBaseUrl(s string) *Client { client.baseUrl = strings.TrimSuffix(s, "/") return client } func (client *Client) SetCookieJar(cookieJar *cookiejar.Jar) *Client { client.client.Jar = cookieJar return client } func (client *Client) SetClient(httpClient *http.Client) *Client { client.client = httpClient if client.cookieJar != nil { client.client.Jar = client.cookieJar } return client } func (client *Client) SetTransport(transport http.RoundTripper) *Client { client.client.Transport = transport return client } func (client *Client) Get(urlPath string) *Request { return newRequest(http.MethodGet, client.stashUri(urlPath), client) } func (client *Client) Put(urlPath string) *Request { return newRequest(http.MethodPut, client.stashUri(urlPath), client) } func (client *Client) Post(urlPath string) *Request { return newRequest(http.MethodPost, client.stashUri(urlPath), client) } func (client *Client) Delete(urlPath string) *Request { return newRequest(http.MethodDelete, client.stashUri(urlPath), client) } func (client *Client) execute(r *Request) (res *http.Response, err error) { var ( n int reader io.Reader ) if r.contentType == "" && r.body != nil { r.contentType = r.detectContentType(r.body) } if r.body != nil { if reader, err = r.readRequestBody(r.contentType, r.body); err != nil { return } } if r.rawRequest, err = http.NewRequest(r.method, r.uri, reader); err != nil { return } for k, vs := range r.header { for _, v := range vs { r.rawRequest.Header.Add(k, v) } } if r.contentType != "" { r.rawRequest.Header.Set("Content-Type", r.contentType) } if client.Authorization != nil { r.rawRequest.Header.Set("Authorization", client.Authorization.Token()) } if r.context != nil { r.rawRequest = r.rawRequest.WithContext(r.context) } n = len(client.interceptorRequest) for i := n - 1; i >= 0; i-- { if err = client.interceptorRequest[i](r.rawRequest); err != nil { return } } if r.rawResponse, err = client.client.Do(r.rawRequest); err != nil { return nil, err } n = len(client.interceptorResponse) for i := n - 1; i >= 0; i-- { if err = client.interceptorResponse[i](r.rawRequest, r.rawResponse); err != nil { _ = r.rawResponse.Body.Close() return } } return r.rawResponse, err } func New() *Client { client := &Client{ client: DefaultClient, interceptorRequest: make([]BeforeRequest, 0, 10), interceptorResponse: make([]AfterRequest, 0, 10), } client.cookieJar, _ = cookiejar.New(nil) client.client.Jar = client.cookieJar return client }