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  }