github.com/qxnw/lib4go@v0.0.0-20180426074627-c80c7e84b925/net/http/http.go (about) 1 package http 2 3 import ( 4 "crypto/rand" 5 "crypto/tls" 6 "crypto/x509" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "net" 11 "net/http" 12 "net/url" 13 "os" 14 "strings" 15 16 "time" 17 18 "github.com/qxnw/lib4go/encoding" 19 ) 20 21 type OptionConf struct { 22 ConnectionTimeout time.Duration 23 RequestTimeout time.Duration 24 } 25 26 //Option 配置选项 27 type Option func(*OptionConf) 28 29 //WithConnTimeout 设置请求超时时长 30 func WithConnTimeout(tm time.Duration) Option { 31 return func(o *OptionConf) { 32 o.ConnectionTimeout = tm 33 } 34 } 35 36 //WithRequestTimeout 设置请求超时时长 37 func WithRequestTimeout(tm time.Duration) Option { 38 return func(o *OptionConf) { 39 o.RequestTimeout = tm 40 } 41 } 42 43 // HTTPClient HTTP客户端 44 type HTTPClient struct { 45 *OptionConf 46 client *http.Client 47 Response *http.Response 48 } 49 50 // HTTPClientRequest http请求 51 type HTTPClientRequest struct { 52 headers map[string]string 53 client *http.Client 54 method string 55 url string 56 params string 57 encoding string 58 } 59 60 // NewHTTPClientCert 根据pem证书初始化httpClient 61 func NewHTTPClientCert(certFile string, keyFile string, caFile string) (client *HTTPClient, err error) { 62 cert, err := tls.LoadX509KeyPair(certFile, keyFile) 63 if err != nil { 64 return 65 } 66 caData, err := ioutil.ReadFile(caFile) 67 if err != nil { 68 return 69 } 70 pool := x509.NewCertPool() 71 pool.AppendCertsFromPEM(caData) 72 ssl := &tls.Config{ 73 Certificates: []tls.Certificate{cert}, 74 RootCAs: pool, 75 } 76 ssl.Rand = rand.Reader 77 client = &HTTPClient{} 78 client.client = &http.Client{ 79 Transport: &http.Transport{ 80 DisableKeepAlives: true, 81 TLSClientConfig: ssl, 82 Dial: func(netw, addr string) (net.Conn, error) { 83 c, err := net.DialTimeout(netw, addr, 0) 84 if err != nil { 85 return nil, err 86 } 87 return c, nil 88 }, 89 MaxIdleConnsPerHost: 0, 90 ResponseHeaderTimeout: 0, 91 }, 92 } 93 return 94 } 95 96 // NewHttpClientCert2 根据ca证书来初始化httpClient 97 func NewHttpClientCert2(caFile string) (client *HTTPClient, err error) { 98 pool := x509.NewCertPool() 99 client = &HTTPClient{} 100 caData, err := ioutil.ReadFile(caFile) 101 if err != nil { 102 fmt.Println("ReadFile err:", err) 103 return 104 } 105 pool.AppendCertsFromPEM(caData) 106 107 client.client = &http.Client{ 108 Transport: &http.Transport{ 109 DisableKeepAlives: true, 110 TLSClientConfig: &tls.Config{RootCAs: pool}, 111 Dial: func(netw, addr string) (net.Conn, error) { 112 c, err := net.DialTimeout(netw, addr, 0) 113 if err != nil { 114 return nil, err 115 } 116 return c, nil 117 }, 118 MaxIdleConnsPerHost: 0, 119 ResponseHeaderTimeout: 0, 120 DisableCompression: true, 121 }, 122 } 123 return 124 } 125 126 // NewHTTPClientCert1 根据ca证书来初始化httpClient 127 func NewHTTPClientCert1(caFile string) (client *HTTPClient, err error) { 128 129 pool := x509.NewCertPool() 130 caData, err := ioutil.ReadFile(caFile) 131 if err != nil { 132 return 133 } 134 pool.AppendCertsFromPEM(caData) 135 client = &HTTPClient{} 136 client.client = &http.Client{ 137 Transport: &http.Transport{ 138 DisableKeepAlives: true, 139 TLSClientConfig: &tls.Config{RootCAs: pool}, 140 Dial: func(netw, addr string) (net.Conn, error) { 141 c, err := net.DialTimeout(netw, addr, 0) 142 if err != nil { 143 return nil, err 144 } 145 return c, nil 146 }, 147 MaxIdleConnsPerHost: 0, 148 ResponseHeaderTimeout: 0, 149 DisableCompression: true, 150 }, 151 } 152 153 return 154 } 155 156 // NewHTTPClient 构建HTTP客户端,用于发送GET POST等请求 157 func NewHTTPClient(opts ...Option) (client *HTTPClient) { 158 client = &HTTPClient{} 159 client.OptionConf = &OptionConf{ConnectionTimeout: time.Second * 3, RequestTimeout: time.Second * 20} 160 for _, opt := range opts { 161 opt(client.OptionConf) 162 } 163 client.client = &http.Client{ 164 Transport: &http.Transport{ 165 DisableKeepAlives: true, 166 Dial: func(netw, addr string) (net.Conn, error) { 167 c, err := net.DialTimeout(netw, addr, client.OptionConf.ConnectionTimeout) 168 if err != nil { 169 return nil, err 170 } 171 c.SetDeadline(time.Now().Add(client.OptionConf.RequestTimeout)) 172 return c, nil 173 }, 174 175 MaxIdleConnsPerHost: 0, 176 ResponseHeaderTimeout: 0, 177 }, 178 } 179 return 180 } 181 182 // NewHTTPClientProxy 根据代理服务器地址创建httpClient 183 func NewHTTPClientProxy(proxy string) (client *HTTPClient) { 184 client = &HTTPClient{} 185 client.client = &http.Client{ 186 Transport: &http.Transport{ 187 DisableKeepAlives: true, 188 Proxy: func(_ *http.Request) (*url.URL, error) { 189 return url.Parse(proxy) //根据定义Proxy func(*Request) (*url.URL, error)这里要返回url.URL 190 }, 191 Dial: func(netw, addr string) (net.Conn, error) { 192 c, err := net.DialTimeout(netw, addr, 0) 193 if err != nil { 194 return nil, err 195 } 196 return c, nil 197 }, 198 MaxIdleConnsPerHost: 0, 199 ResponseHeaderTimeout: 0, 200 }, 201 } 202 return 203 } 204 205 // Download 发送http请求, method:http请求方法包括:get,post,delete,put等 url: 请求的HTTP地址,不包括参数,params:请求参数, 206 // header,http请求头多个用/n分隔,每个键值之前用=号连接 207 func (c *HTTPClient) Download(method string, url string, params string, header map[string]string) (body []byte, status int, err error) { 208 req, err := http.NewRequest(strings.ToUpper(method), url, strings.NewReader(params)) 209 if err != nil { 210 return 211 } 212 req.Close = true 213 for i, v := range header { 214 req.Header.Set(i, v) 215 } 216 c.Response, err = c.client.Do(req) 217 if c.Response != nil { 218 defer c.Response.Body.Close() 219 } 220 if err != nil { 221 return 222 } 223 status = c.Response.StatusCode 224 body, err = ioutil.ReadAll(c.Response.Body) 225 return 226 } 227 228 // Save 发送http请求, method:http请求方法包括:get,post,delete,put等 url: 请求的HTTP地址,不包括参数,params:请求参数, 229 // header,http请求头多个用/n分隔,每个键值之前用=号连接 230 func (c *HTTPClient) Save(method string, url string, params string, header map[string]string, path string) (status int, err error) { 231 body, status, err := c.Download(method, url, params, header) 232 if err != nil { 233 return 234 } 235 fl, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0664) 236 if err != nil { 237 return 238 } 239 defer fl.Close() 240 n, err := fl.Write(body) 241 if err == nil && n < len(body) { 242 err = io.ErrShortWrite 243 } 244 return 245 } 246 247 // Request 发送http请求, method:http请求方法包括:get,post,delete,put等 url: 请求的HTTP地址,不包括参数,params:请求参数, 248 // header,http请求头多个用/n分隔,每个键值之前用=号连接 249 func (c *HTTPClient) Request(method string, url string, params string, charset string, header map[string]string) (content string, status int, err error) { 250 req, err := http.NewRequest(strings.ToUpper(method), url, strings.NewReader(params)) 251 if err != nil { 252 return 253 } 254 req.Close = true 255 for i, v := range header { 256 req.Header.Set(i, v) 257 } 258 c.Response, err = c.client.Do(req) 259 if c.Response != nil { 260 defer c.Response.Body.Close() 261 } 262 if err != nil { 263 return 264 } 265 body, err := ioutil.ReadAll(c.Response.Body) 266 if err != nil { 267 return 268 } 269 status = c.Response.StatusCode 270 content, err = encoding.Convert(body, charset) 271 return 272 } 273 274 // Get http get请求 275 func (c *HTTPClient) Get(url string, args ...string) (content string, status int, err error) { 276 charset := getEncoding(args...) 277 c.Response, err = c.client.Get(url) 278 if c.Response != nil { 279 defer c.Response.Body.Close() 280 } 281 if err != nil { 282 return 283 } 284 body, err := ioutil.ReadAll(c.Response.Body) 285 if err != nil { 286 return 287 } 288 status = c.Response.StatusCode 289 content, err = encoding.Convert(body, charset) 290 return 291 } 292 293 // Post http Post请求 294 func (c *HTTPClient) Post(url string, params string, args ...string) (content string, status int, err error) { 295 charset := getEncoding(args...) 296 c.Response, err = c.client.Post(url, fmt.Sprintf("application/x-www-form-urlencoded;charset=%s", charset), encoding.GetReader(params, charset)) 297 if c.Response != nil { 298 defer c.Response.Body.Close() 299 } 300 if err != nil { 301 return 302 } 303 body, err := ioutil.ReadAll(c.Response.Body) 304 if err != nil { 305 return 306 } 307 status = c.Response.StatusCode 308 content, err = encoding.Convert(body, charset) 309 return 310 } 311 312 func getEncoding(params ...string) (encoding string) { 313 if len(params) > 0 { 314 encoding = strings.ToUpper(params[0]) 315 return 316 } 317 return "UTF-8" 318 }