1 Star 0 Fork 1

CHUAN/go-scaffold

forked from Allen/go-scaffold 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
request.go 5.58 KB
一键复制 编辑 原始数据 按行查看 历史
JHC 提交于 2022-07-08 22:16 . update package name
package client
import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"gitee.com/chuanmension/go-scaffold/util"
"io/ioutil"
"net"
"net/http"
"net/url"
"path"
"strings"
"time"
"go.uber.org/zap"
)
const retryCount = 3
const retrySleepSecond = 1
var httpClient *http.Client
// ErrBadRequest for request data error
var ErrBadRequest = errors.New("bad request")
// BaseAPI for api client
type BaseAPI struct {
Host string
// global header will send in each request
Headers map[string]string
// URLPrefix after host:port
URLPrefix string
RetryCount int
RetrySleepSecond int
}
// RequestForm for package request data
type RequestForm struct {
URL string `form:"url" json:"url"`
URI string `form:"uri" json:"uri"`
Method string `form:"method" json:"method"`
Params map[string]string `form:"params" json:"params"`
Data interface{} `form:"data" json:"data"`
Headers map[string]string `form:"headers" json:"headers"`
}
// Response for package response body
type Response struct {
Content []byte
Status int
}
// ToJSON format response content to map
func (r *Response) ToJSON() map[string]interface{} {
var data map[string]interface{}
err := json.Unmarshal(r.Content, &data)
if err != nil {
zap.L().Error("Response to json error", zap.String("error", err.Error()))
}
return data
}
// Get request
func (s *BaseAPI) Get(uri string, params map[string]string, headers map[string]string) (*Response, error) {
form := &RequestForm{URI: uri, Method: http.MethodGet, Params: params, Headers: headers}
return s.RequestWithRetry(form)
}
// Post request
func (s *BaseAPI) Post(uri string, params map[string]string, headers map[string]string, data interface{}) (*Response, error) {
form := &RequestForm{URI: uri, Method: http.MethodPost, Params: params, Headers: headers, Data: data}
return s.RequestWithRetry(form)
}
// Delete request
func (s *BaseAPI) Delete(uri string, params map[string]string, headers map[string]string, data interface{}) (*Response, error) {
form := &RequestForm{URI: uri, Method: http.MethodDelete, Params: params, Headers: headers, Data: data}
return s.RequestWithRetry(form)
}
// Put request
func (s *BaseAPI) Put(uri string, params map[string]string, headers map[string]string, data interface{}) (*Response, error) {
form := &RequestForm{URI: uri, Method: http.MethodPut, Params: params, Headers: headers, Data: data}
return s.RequestWithRetry(form)
}
// RequestWithRetry do
func (s *BaseAPI) RequestWithRetry(r *RequestForm) (*Response, error) {
var resp *Response
var err error
count := util.MaxInt(s.RetryCount, retryCount)
sleep := util.MaxInt(retrySleepSecond, s.RetrySleepSecond)
for i := 0; i < count; i++ {
resp, err = s.Request(r)
if err == nil {
break
}
zap.L().Error("RequestWithRetry called", zap.Int("count", i), zap.String("error", err.Error()))
time.Sleep(time.Duration(sleep) * time.Second)
}
return resp, err
}
// Request send to remote host
// request form contains:
// method in [GET POST DELETE PUT]
// url or uri
// params = query parameter
// data = post data
// headers
func (s *BaseAPI) Request(req *RequestForm) (*Response, error) {
var request *http.Request
var err error
method := strings.ToUpper(req.Method)
// check url or from Host join uri
if req.URL == "" {
if strings.HasPrefix(req.URI, "http") {
req.URL = req.URI
} else {
// url join
u, _ := url.Parse(s.Host)
u.Path = path.Join(u.Path, s.URLPrefix, req.URI)
req.URL = u.String()
}
}
// new http request
if req.Data != nil {
switch req.Data.(type) {
case string:
// set post json
request, err = http.NewRequest(method, req.URL, bytes.NewBuffer([]byte(req.Data.(string))))
request.Header.Set("Content-Type", "application/json;charset=utf-8")
case map[string]interface{}:
// set post form
postForm := url.Values{}
for k, v := range req.Data.(map[string]interface{}) {
postForm.Add(k, fmt.Sprintf("%v", v))
}
request, err = http.NewRequest(method, req.URL, strings.NewReader(postForm.Encode()))
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
case *bytes.Buffer:
request, err = http.NewRequest(method, req.URL, req.Data.(*bytes.Buffer))
default:
return nil, ErrBadRequest
}
} else {
request, err = http.NewRequest(method, req.URL, nil)
}
// check new request error
if err != nil {
return nil, err
}
// set request params
if req.Params != nil {
params := request.URL.Query()
for k, v := range req.Params {
params.Add(k, v)
}
request.URL.RawQuery = params.Encode()
}
// set default header
if s.Headers != nil {
for k, v := range s.Headers {
// set custom host
if strings.ToUpper(k) == "HOST" {
request.Host = v
continue
}
request.Header.Set(k, v)
}
}
// set request header
if req.Headers != nil {
for k, v := range req.Headers {
request.Header.Set(k, v)
}
}
var resp *http.Response
// send requests
resp, err = httpClient.Do(request)
if err != nil {
return nil, err
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return &Response{Content: content, Status: resp.StatusCode}, nil
}
func init() {
// init http client
var netTransport = &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
TLSHandshakeTimeout: 5 * time.Second,
ResponseHeaderTimeout: 5 * time.Second,
ExpectContinueTimeout: 5 * time.Second,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
httpClient = &http.Client{
Timeout: 5 * time.Second,
Transport: netTransport,
}
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/chuanmension/go-scaffold.git
git@gitee.com:chuanmension/go-scaffold.git
chuanmension
go-scaffold
go-scaffold
v1.0.8

搜索帮助