在日常开发中常常会用到http库来发送申请,就将罕用的申请办法封装了一个库,灵便又好用。这里用到了建造者模式,相似的应用场景都能够这样来实现:
具体实现
package requestsimport ( "bytes" "context" "encoding/json" "errors" "fmt" "io/ioutil" "net/http" "net/url" "strings" "time")const ( contentType = "Content-Type")type HttpSend struct { ctx context.Context // 上下文 client *http.Client // 客户端 request *http.Request // 申请体 url, httpProxy string // 申请门路 getValue interface{} // get申请体 postValue interface{} // post申请体 postFormValue url.Values // form-data post申请体 header map[string]string // header timeout time.Duration // 超时工夫 tryNum int // 重试次数 doNum int // 已重试次数 intervalTime time.Duration // 重试间隔时间 err error // 谬误}// 应用建造者模式初始化HttpClientfunc NewHttpClient(ctx context.Context, options ...HttpOptions) *HttpSend { client := new(HttpSend) client.ctx = ctx for i := 0; i < len(options); i++ { options[i](client) } client.NewClient(ctx) if client.timeout != 0 { client.client.Timeout = client.timeout } return client}// 实例化HttpClientfunc (h *HttpSend) NewClient(ctx context.Context) { h.client = new(http.Client) if h.httpProxy != "" { var proxyUrl *url.URL proxyUrl, h.err = url.Parse(h.httpProxy) if h.err != nil { log.Errorf(ctx, fmt.Sprintf("初始化httpClient-httpProxy解析谬误, error:%s", h.err)) } h.client.Transport = &http.Transport{ Proxy: http.ProxyURL(proxyUrl), } }}// 包装了重试的do办法func (h *HttpSend) HttpDo() []byte { var resp *http.Response var body []byte resp, h.err = h.client.Do(h.request) if h.err == nil { log.Infof(h.ctx, fmt.Sprintf("HttpDo,resp:%+v, error:%+v", resp, h.err)) defer resp.Body.Close() if resp.StatusCode == http.StatusOK { body, h.err = ioutil.ReadAll(resp.Body) } else { h.err = errors.New(resp.Status) } } else { for h.doNum < h.tryNum { h.doNum++ log.Errorf(h.ctx, fmt.Sprintf("HttpDo,url:%s,resp:%+v,重试次数:%d,error:%s", h.url, resp, h.doNum, h.err)) time.Sleep(h.intervalTime) h.NewClient(h.ctx) body = h.HttpDo() return body } } return body}// 发送get申请func (h *HttpSend) HttpGet() ([]byte, error) { if h.err != nil { return []byte{}, h.err } defer func(t time.Time) { log.Info(h.ctx, fmt.Sprintf("took %v/s", time.Since(t).Seconds())) }(time.Now()) log.Info(h.ctx, fmt.Sprintf("url:%s,request:%s", h.url, h.url)) h.request, h.err = http.NewRequest(http.MethodGet, h.url, nil) if h.err != nil { return []byte{}, h.err } h.setHeader() var body []byte body = h.HttpDo() log.Infof(h.ctx, fmt.Sprintf("url:%s,response:%s,error:%s", h.url, string(body), h.err)) return body, h.err}// 发送json参数的get申请func (h *HttpSend) HttpGetWithJson() ([]byte, error) { if h.err != nil { return []byte{}, h.err } getValue, err := json.Marshal(h.getValue) if err != nil { log.Errorf(h.ctx, fmt.Sprintf("err:%s", err)) return nil, err } log.Infof(h.ctx, fmt.Sprintf("url:%s,request:%+v", h.url, h.getValue)) h.request, h.err = http.NewRequest(http.MethodGet, h.url, strings.NewReader(string(getValue))) if _, ok := h.header[contentType]; !ok { h.request.Header.Set(contentType, "application/json") } h.setHeader() var body []byte body = h.HttpDo() log.Infof(h.ctx, fmt.Sprintf("url:%s,response:%s,error:%s", h.url, string(body), h.err)) return body, h.err}// 发送json格局的post申请func (h *HttpSend) HttpPost() ([]byte, error) { if h.err != nil { return []byte{}, h.err } postValue, err := json.Marshal(h.postValue) if err != nil { log.Errorf(h.ctx, fmt.Sprintf("err:%s", err)) return nil, err } log.Infof(h.ctx, fmt.Sprintf("url:%s,request:%s", h.url, h.postValue)) h.request, h.err = http.NewRequest(http.MethodPost, h.url, strings.NewReader(string(postValue))) if _, ok := h.header[contentType]; !ok { h.request.Header.Set(contentType, "application/json") } h.setHeader() var body []byte body = h.HttpDo() log.Infof(h.ctx, fmt.Sprintf("url:%s,response:%s", h.url, string(body))) return body, h.err}// 发送form-data的post申请func (h *HttpSend) HttpPostForm() ([]byte, error) { if h.err != nil { return []byte{}, h.err } log.Infof(h.ctx, fmt.Sprintf("url:%s,postValue:%+v", h.url, h.postFormValue)) h.request, h.err = http.NewRequest(http.MethodPost, h.url, strings.NewReader(h.postFormValue.Encode())) if h.err != nil { return []byte{}, h.err } h.request.Header.Set(contentType, "application/x-www-form-urlencoded") var body []byte body = h.HttpDo() log.Infof(h.ctx, fmt.Sprintf("send post success,body:%s,h.err:%s", string(body), h.err)) return body, h.err}// 设置headerfunc (h *HttpSend) setHeader() { for k, v := range h.header { h.request.Header.Set(k, v) }}type HttpOptions func(*HttpSend)// 设置申请门路func UrlOptions(url string) HttpOptions { return func(client *HttpSend) { client.url = url }}// 设置post申请体func PostValueOptions(postValue interface{}) HttpOptions { return func(client *HttpSend) { client.postValue = postValue }}// 设置form-data格局的post申请体func PostFormValueOptions(postFormValue url.Values) HttpOptions { return func(client *HttpSend) { client.postFormValue = postFormValue }}// 设置get申请体func GetValueOptions(getValue interface{}) HttpOptions { return func(client *HttpSend) { client.getValue = getValue }}// 设置超时工夫func TimeOptions(timeout time.Duration) HttpOptions { return func(client *HttpSend) { client.timeout = timeout }}// 设置代理func ProxyOptions(proxy string) HttpOptions { return func(client *HttpSend) { client.httpProxy = proxy }}// 设置申请头func HeaderOptions(header map[string]string) HttpOptions { return func(client *HttpSend) { client.header = header }}// 设置重试参数func TryOptions(tryNum int, intervalTime time.Duration) HttpOptions { return func(client *HttpSend) { client.tryNum = tryNum client.intervalTime = intervalTime }}
应用
data, err := requests.NewHttpClient( ctx, requests.UrlOptions(xxxUrl), requests.PostValueOptions(postParams), requests.TryOptions(2, time.Second*3)). HttpPost()