package httputil import ( "errors" "io" "net" "net/http" "net/url" "strconv" "sync" "time" ) const defaultTimeOut = 10 var ( defaultClient *http.Client httpClientMap sync.Map errProxyNil = errors.New("proxy is nil") ) func init() { defaultClient = &http.Client{ Timeout: time.Second * time.Duration(defaultTimeOut), Transport: &http.Transport{ Proxy: http.ProxyFromEnvironment, DialContext: (&net.Dialer{ Timeout: time.Second * 30, KeepAlive: time.Second * 30, }).DialContext, ForceAttemptHTTP2: true, MaxIdleConns: 100, MaxIdleConnsPerHost: 100, IdleConnTimeout: time.Second * 90, TLSHandshakeTimeout: time.Second * 10, ExpectContinueTimeout: time.Second, }, } } // 传入参数单位秒 func getClientByTimeoutSet(connTimeout int) *http.Client { if connTimeout == defaultTimeOut { return defaultClient } client, _ := httpClientMap.LoadOrStore(connTimeout, &http.Client{ Timeout: time.Duration(connTimeout) * time.Second, Transport: &http.Transport{ Proxy: http.ProxyFromEnvironment, DialContext: (&net.Dialer{ Timeout: time.Second * 30, KeepAlive: time.Second * 30, }).DialContext, ForceAttemptHTTP2: true, MaxIdleConns: 100, MaxIdleConnsPerHost: 100, IdleConnTimeout: time.Second * 90, TLSHandshakeTimeout: time.Second * 10, ExpectContinueTimeout: time.Second, }, }) return client.(*http.Client) } type ProxyCfg struct { Host string Timeout int //秒 Source string IsActive bool //是否开启代理 } func (p *ProxyCfg) Build(rawurl string, rawHeaders map[string]string) (string, map[string]string, error) { if !p.IsActive { return rawurl, rawHeaders, nil } u, err := url.Parse(rawurl) if err != nil { return "", nil, err } target := url.URL{Scheme: u.Scheme, Host: u.Host} u.Host = p.Host u.Scheme = "http" m := make(map[string]string) m["X-Proxy-Target-Host"] = target.String() m["X-Proxy-Source"] = "ys" if p.Timeout > 0 { m["X-Proxy-Timeout"] = strconv.Itoa(p.Timeout) } if len(rawHeaders) > 0 { for k, v := range rawHeaders { m[k] = v } } return u.String(), m, nil } // 提供关闭函数以防止内存泄露 func IgnoreResp(resp *http.Response) { _, _ = io.Copy(io.Discard, resp.Body) resp.Body.Close() }