在日常开发中常常会用到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()