@@ -0,0 +1,101 @@
|
||||
package httputil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const defaultTimeOut = 10
|
||||
|
||||
var (
|
||||
defaultClient *http.Client
|
||||
httpClientMap sync.Map
|
||||
errProxyNil = errors.New("proxy is nil")
|
||||
)
|
||||
|
||||
func init() {
|
||||
defaultClient = &http.Client{
|
||||
Timeout: time.Second * time.Duration(defaultTimeOut),
|
||||
Transport: &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: time.Second * 30,
|
||||
KeepAlive: time.Second * 30,
|
||||
}).DialContext,
|
||||
ForceAttemptHTTP2: true,
|
||||
MaxIdleConns: 100,
|
||||
MaxIdleConnsPerHost: 100,
|
||||
IdleConnTimeout: time.Second * 90,
|
||||
TLSHandshakeTimeout: time.Second * 10,
|
||||
ExpectContinueTimeout: time.Second,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 传入参数单位秒
|
||||
func getClientByTimeoutSet(connTimeout int) *http.Client {
|
||||
if connTimeout == defaultTimeOut {
|
||||
return defaultClient
|
||||
}
|
||||
client, _ := httpClientMap.LoadOrStore(connTimeout, &http.Client{
|
||||
Timeout: time.Duration(connTimeout) * time.Second,
|
||||
Transport: &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: time.Second * 30,
|
||||
KeepAlive: time.Second * 30,
|
||||
}).DialContext,
|
||||
ForceAttemptHTTP2: true,
|
||||
MaxIdleConns: 100,
|
||||
MaxIdleConnsPerHost: 100,
|
||||
IdleConnTimeout: time.Second * 90,
|
||||
TLSHandshakeTimeout: time.Second * 10,
|
||||
ExpectContinueTimeout: time.Second,
|
||||
},
|
||||
})
|
||||
return client.(*http.Client)
|
||||
}
|
||||
|
||||
type ProxyCfg struct {
|
||||
Host string
|
||||
Timeout int //秒
|
||||
Source string
|
||||
IsActive bool //是否开启代理
|
||||
}
|
||||
|
||||
func (p *ProxyCfg) Build(rawurl string, rawHeaders map[string]string) (string, map[string]string, error) {
|
||||
if !p.IsActive {
|
||||
return rawurl, rawHeaders, nil
|
||||
}
|
||||
u, err := url.Parse(rawurl)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
target := url.URL{Scheme: u.Scheme, Host: u.Host}
|
||||
u.Host = p.Host
|
||||
u.Scheme = "http"
|
||||
m := make(map[string]string)
|
||||
m["X-Proxy-Target-Host"] = target.String()
|
||||
m["X-Proxy-Source"] = "ys"
|
||||
if p.Timeout > 0 {
|
||||
m["X-Proxy-Timeout"] = strconv.Itoa(p.Timeout)
|
||||
}
|
||||
if len(rawHeaders) > 0 {
|
||||
for k, v := range rawHeaders {
|
||||
m[k] = v
|
||||
}
|
||||
}
|
||||
return u.String(), m, nil
|
||||
}
|
||||
|
||||
// 提供关闭函数以防止内存泄露
|
||||
func IgnoreResp(resp *http.Response) {
|
||||
_, _ = io.Copy(io.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package httputil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ClientGet(connTimeout int, url string, headers map[string]string, params ...any) (*http.Response, error) {
|
||||
for _, p := range params {
|
||||
url = addParams(url, toUrlValues(p))
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
cl := getClientByTimeoutSet(connTimeout)
|
||||
return cl.Do(req)
|
||||
}
|
||||
|
||||
func DefaultClientGet(url string, headers map[string]string, params ...any) (*http.Response, error) {
|
||||
return ClientGet(defaultTimeOut, url, headers, params...)
|
||||
}
|
||||
|
||||
func ClientGetBytes(connTimeout int, url string, headers map[string]string, params ...any) (int, []byte, error) {
|
||||
resp, err := ClientGet(connTimeout, url, headers, params...)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
ct, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return resp.StatusCode, nil, err
|
||||
}
|
||||
return resp.StatusCode, ct, nil
|
||||
}
|
||||
|
||||
func DefaultClientGetBytes(url string, headers map[string]string, params ...any) (int, []byte, error) {
|
||||
return ClientGetBytes(defaultTimeOut, url, headers, params...)
|
||||
}
|
||||
|
||||
func ClientGetBytesWithProxy(connTimeout int, p *ProxyCfg, url string, headers map[string]string, params ...any) (int, []byte, error) {
|
||||
if p == nil {
|
||||
return 0, nil, errProxyNil
|
||||
}
|
||||
pUrl, pHeaders, err := p.Build(url, headers)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
return ClientGetBytes(connTimeout, pUrl, pHeaders, params...)
|
||||
}
|
||||
|
||||
func ClientGetWithRespWithProxy(connTimeout int, p *ProxyCfg, bind any, url string, headers map[string]string, params ...any) (int, error) {
|
||||
code, bts, err := ClientGetBytesWithProxy(connTimeout, p, url, headers, params...)
|
||||
if err != nil {
|
||||
return code, err
|
||||
}
|
||||
return code, json.Unmarshal(bts, &bind)
|
||||
}
|
||||
|
||||
func DefaultClientGetWithRespWithProxy(p *ProxyCfg, bind any, url string, headers map[string]string, params ...any) (int, error) {
|
||||
return ClientGetWithRespWithProxy(defaultTimeOut, p, bind, url, headers, params...)
|
||||
}
|
||||
|
||||
func ClientGetWithResp(bind any, connTimeout int, url string, headers map[string]string, params ...any) (int, error) {
|
||||
code, ct, err := ClientGetBytes(connTimeout, url, headers, params...)
|
||||
if err != nil {
|
||||
return code, err
|
||||
}
|
||||
return code, json.Unmarshal(ct, &bind)
|
||||
}
|
||||
|
||||
func DefaultClientGetWithResp(bind any, url string, headers map[string]string, params ...any) (int, error) {
|
||||
return ClientGetWithResp(bind, defaultTimeOut, url, headers, params...)
|
||||
}
|
||||
|
||||
func ClientGetWithRespWithCtx(ctx context.Context, bind any, connTimeout int, url string, headers map[string]string, params ...any) (int, error) {
|
||||
code, ct, err := ClientGetBytesWithCtx(ctx, connTimeout, url, headers, params...)
|
||||
if err != nil {
|
||||
return code, err
|
||||
}
|
||||
return code, json.Unmarshal(ct, &bind)
|
||||
}
|
||||
|
||||
func DefaultClientGetWithRespWithCtx(ctx context.Context, bind any, url string, headers map[string]string, params ...any) (int, error) {
|
||||
code, ct, err := ClientGetBytesWithCtx(ctx, defaultTimeOut, url, headers, params...)
|
||||
if err != nil {
|
||||
return code, err
|
||||
}
|
||||
return code, json.Unmarshal(ct, &bind)
|
||||
}
|
||||
|
||||
func ClientGetWithCtx(ctx context.Context, connTimeout int, url string, headers map[string]string, params ...any) (*http.Response, error) {
|
||||
for _, p := range params {
|
||||
url = addParams(url, toUrlValues(p))
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range headers {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
cl := getClientByTimeoutSet(connTimeout)
|
||||
return cl.Do(req)
|
||||
}
|
||||
|
||||
func DefaultClientGetWithCtx(ctx context.Context, url string, headers map[string]string, params ...any) (*http.Response, error) {
|
||||
return ClientGetWithCtx(ctx, defaultTimeOut, url, headers, params...)
|
||||
}
|
||||
|
||||
func ClientGetBytesWithCtx(ctx context.Context, connTimeout int, url string, headers map[string]string, params ...any) (int, []byte, error) {
|
||||
resp, err := ClientGetWithCtx(ctx, connTimeout, url, headers, params...)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
ct, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return resp.StatusCode, nil, err
|
||||
}
|
||||
return resp.StatusCode, ct, nil
|
||||
}
|
||||
|
||||
func DefaultClientGetBytesWithCtx(ctx context.Context, url string, headers map[string]string, params ...any) (int, []byte, error) {
|
||||
return ClientGetBytesWithCtx(ctx, defaultTimeOut, url, headers, params...)
|
||||
}
|
||||
|
||||
func toUrlValues(v interface{}) url.Values {
|
||||
switch t := v.(type) {
|
||||
case url.Values:
|
||||
return t
|
||||
case map[string][]string:
|
||||
return url.Values(t)
|
||||
case map[string]string:
|
||||
rst := make(url.Values)
|
||||
for k, v := range t {
|
||||
rst.Add(k, v)
|
||||
}
|
||||
return rst
|
||||
case map[string]interface{}:
|
||||
rst := make(url.Values)
|
||||
for k, v := range t {
|
||||
rst.Add(k, fmt.Sprintf("%v", v))
|
||||
}
|
||||
return rst
|
||||
case nil:
|
||||
return make(url.Values)
|
||||
default:
|
||||
panic("Invalid value")
|
||||
}
|
||||
}
|
||||
|
||||
func addParams(url_ string, params url.Values) string {
|
||||
if len(params) == 0 {
|
||||
return url_
|
||||
}
|
||||
if !strings.Contains(url_, "?") {
|
||||
url_ += "?"
|
||||
}
|
||||
if strings.HasSuffix(url_, "?") || strings.HasSuffix(url_, "&") {
|
||||
url_ += params.Encode()
|
||||
} else {
|
||||
url_ += "&" + params.Encode()
|
||||
}
|
||||
return url_
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package httputil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ClientPost(connTimeout int, url string, headers map[string]string, data any) (*http.Response, error) {
|
||||
req, err := getPostRequest(url, headers, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cl := getClientByTimeoutSet(connTimeout)
|
||||
return cl.Do(req)
|
||||
}
|
||||
|
||||
func DefaultClientPost(url string, headers map[string]string, data any) (*http.Response, error) {
|
||||
return ClientPost(defaultTimeOut, url, headers, data)
|
||||
}
|
||||
|
||||
func ClientPostWithCtx(ctx context.Context, connTimeout int, url string, headers map[string]string, data any) (*http.Response, error) {
|
||||
req, err := getPostRequest(url, headers, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
cl := getClientByTimeoutSet(connTimeout)
|
||||
return cl.Do(req)
|
||||
}
|
||||
|
||||
func DefaultClientPostWithCtx(ctx context.Context, url string, headers map[string]string, data any) (*http.Response, error) {
|
||||
return ClientPostWithCtx(ctx, defaultTimeOut, url, headers, data)
|
||||
}
|
||||
|
||||
func ClientPostWithProxy(connTimeout int, p *ProxyCfg, url string, headers map[string]string, data any) (*http.Response, error) {
|
||||
if p == nil {
|
||||
return nil, errProxyNil
|
||||
}
|
||||
pUrl, pHeaders, err := p.Build(url, headers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ClientPost(connTimeout, pUrl, pHeaders, data)
|
||||
}
|
||||
|
||||
func ClientPostWithResp(connTimeout int, bind any, url string, headers map[string]string, data any) (int, error) {
|
||||
resp, err := ClientPost(connTimeout, url, headers, data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ct, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return resp.StatusCode, err
|
||||
}
|
||||
return resp.StatusCode, json.Unmarshal(ct, &bind)
|
||||
}
|
||||
|
||||
func DefaultClientPostWithResp(bind any, url string, headers map[string]string, data any) (int, error) {
|
||||
return ClientPostWithResp(defaultTimeOut, bind, url, headers, data)
|
||||
}
|
||||
|
||||
func ClientPostWithRespWithCtx(ctx context.Context, connTimeout int, bind any, url string, headers map[string]string, data any) (int, error) {
|
||||
resp, err := ClientPostWithCtx(ctx, connTimeout, url, headers, data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ct, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return resp.StatusCode, err
|
||||
}
|
||||
return resp.StatusCode, json.Unmarshal(ct, &bind)
|
||||
}
|
||||
|
||||
func DefaultClientPostWithRespWithCtx(ctx context.Context, bind any, url string, headers map[string]string, data any) (int, error) {
|
||||
return ClientPostWithRespWithCtx(ctx, defaultTimeOut, bind, url, headers, data)
|
||||
}
|
||||
|
||||
func ClientPostWithRespWithProxy(connTimeout int, p *ProxyCfg, bind any, url string, headers map[string]string, data any) (int, error) {
|
||||
resp, err := ClientPostWithProxy(connTimeout, p, url, headers, data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ct, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return resp.StatusCode, err
|
||||
}
|
||||
return resp.StatusCode, json.Unmarshal(ct, &bind)
|
||||
}
|
||||
|
||||
func DefaultClientPostWithRespWithProxy(p *ProxyCfg, bind any, url string, headers map[string]string, data any) (int, error) {
|
||||
return ClientPostWithRespWithProxy(defaultTimeOut, p, &bind, url, headers, data)
|
||||
}
|
||||
|
||||
func getPostRequest(url string, headers map[string]string, data any) (*http.Request, error) {
|
||||
switch data.(type) {
|
||||
case []byte, string, *bytes.Reader, *bytes.Buffer:
|
||||
req, err := http.NewRequest(http.MethodPost, url, toReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
return req, nil
|
||||
default:
|
||||
}
|
||||
paramsValues := toUrlValues(data)
|
||||
if checkParamFile(paramsValues) {
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
for k, v := range paramsValues {
|
||||
for _, vv := range v {
|
||||
// is file
|
||||
if k[0] == '@' {
|
||||
if err := addFormFile(writer, k[1:], vv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
_ = writer.WriteField(k, vv)
|
||||
}
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodPost, url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
if err = writer.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(paramsValues.Encode()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func toReader(v interface{}) *bytes.Reader {
|
||||
switch t := v.(type) {
|
||||
case []byte:
|
||||
return bytes.NewReader(t)
|
||||
case string:
|
||||
return bytes.NewReader([]byte(t))
|
||||
case *bytes.Buffer:
|
||||
return bytes.NewReader(t.Bytes())
|
||||
case *bytes.Reader:
|
||||
return t
|
||||
case nil:
|
||||
return bytes.NewReader(nil)
|
||||
default:
|
||||
panic("Invalid value")
|
||||
}
|
||||
}
|
||||
|
||||
// Does the params contain a file?
|
||||
func checkParamFile(params url.Values) bool {
|
||||
for k := range params {
|
||||
if k[0] == '@' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Add a file to a multipart writer.
|
||||
func addFormFile(writer *multipart.Writer, name, path string) error {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
part, err := writer.CreateFormFile(name, filepath.Base(path))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(part, file)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package httputil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func ClientPostJson(connTimeout int, url string, headers map[string]string, data any) (*http.Response, error) {
|
||||
body, err := dataToJsonReader(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodPost, url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
cl := getClientByTimeoutSet(connTimeout)
|
||||
return cl.Do(req)
|
||||
}
|
||||
|
||||
func DefaultClientPostJson(url string, headers map[string]string, data any) (*http.Response, error) {
|
||||
return ClientPostJson(defaultTimeOut, url, headers, data)
|
||||
}
|
||||
|
||||
func ClientPostJsonWithProxy(connTimeout int, p *ProxyCfg, url string, headers map[string]string, params any) (*http.Response, error) {
|
||||
if p == nil {
|
||||
return nil, errProxyNil
|
||||
}
|
||||
pUrl, pHeaders, err := p.Build(url, headers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ClientPostJson(connTimeout, pUrl, pHeaders, params)
|
||||
}
|
||||
|
||||
func DefaultClientPostJsonWithProxy(p *ProxyCfg, url string, headers map[string]string, params any) (*http.Response, error) {
|
||||
return ClientPostJsonWithProxy(defaultTimeOut, p, url, headers, params)
|
||||
}
|
||||
|
||||
func ClientPostJsonWithRespWithProxy(connTimeout int, p *ProxyCfg, bind any, url string, headers map[string]string, data any) (int, error) {
|
||||
resp, err := ClientPostJsonWithProxy(connTimeout, p, url, headers, data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ct, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return resp.StatusCode, err
|
||||
}
|
||||
return resp.StatusCode, json.Unmarshal(ct, &bind)
|
||||
}
|
||||
|
||||
func DefaultClientPostJsonWithRespWithProxy(p *ProxyCfg, bind any, url string, headers map[string]string, data any) (int, error) {
|
||||
return ClientPostJsonWithRespWithProxy(defaultTimeOut, p, bind, url, headers, data)
|
||||
}
|
||||
|
||||
func ClientPostJsonWithResp(connTimeout int, bind any, url string, headers map[string]string, data any) (int, error) {
|
||||
resp, err := ClientPostJson(connTimeout, url, headers, data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ct, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return resp.StatusCode, err
|
||||
}
|
||||
return resp.StatusCode, json.Unmarshal(ct, &bind)
|
||||
}
|
||||
|
||||
func DefaultClientPostJsonWithResp(bind any, url string, headers map[string]string, data any) (int, error) {
|
||||
return ClientPostJsonWithResp(defaultTimeOut, bind, url, headers, data)
|
||||
}
|
||||
|
||||
func ClientPostJsonWithCtx(ctx context.Context, connTimeout int, url string, headers map[string]string, data any) (*http.Response, error) {
|
||||
cl := getClientByTimeoutSet(connTimeout)
|
||||
body, err := dataToJsonReader(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodPost, url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
return cl.Do(req)
|
||||
}
|
||||
|
||||
func DefaultClientPostJsonWithCtx(ctx context.Context, url string, headers map[string]string, data any) (*http.Response, error) {
|
||||
return ClientPostJsonWithCtx(ctx, defaultTimeOut, url, headers, data)
|
||||
}
|
||||
|
||||
func ClientPostJsonWithRespWithCtx(ctx context.Context, bind any, connTimeout int, url string, headers map[string]string, data any) (int, error) {
|
||||
resp, err := ClientPostJsonWithCtx(ctx, connTimeout, url, headers, data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ct, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return resp.StatusCode, err
|
||||
}
|
||||
return resp.StatusCode, json.Unmarshal(ct, &bind)
|
||||
}
|
||||
|
||||
func DefaultClientPostJsonWithRespWithCtx(ctx context.Context, bind any, url string, headers map[string]string, data any) (int, error) {
|
||||
return ClientPostJsonWithRespWithCtx(ctx, bind, defaultTimeOut, url, headers, data)
|
||||
}
|
||||
|
||||
func dataToJsonReader(data any) (*bytes.Reader, error) {
|
||||
var body []byte
|
||||
switch t := data.(type) {
|
||||
case []byte:
|
||||
body = t
|
||||
case string:
|
||||
body = []byte(t)
|
||||
default:
|
||||
var err error
|
||||
body, err = json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return bytes.NewReader(body), nil
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
package httputil
|
||||
|
||||
import (
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/middleware/requestid"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/ddliu/go-httpclient"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// HTTPClient htttp客户端
|
||||
type HTTPClient struct {
|
||||
client *httpclient.HttpClient
|
||||
}
|
||||
|
||||
func NewHTTPClient(client *httpclient.HttpClient) *HTTPClient {
|
||||
return &HTTPClient{client}
|
||||
}
|
||||
|
||||
type httpClientPool struct {
|
||||
cliPool map[string]*httpclient.HttpClient
|
||||
poolSize int
|
||||
offset int
|
||||
}
|
||||
|
||||
// HTTPResponse http响应
|
||||
type HTTPResponse struct {
|
||||
StatusCode int `json:"statusCode"`
|
||||
Body *httpclient.Response `json:"boby"`
|
||||
}
|
||||
|
||||
var httpCliPool = httpClientPool{cliPool: map[string]*httpclient.HttpClient{}, poolSize: 50}
|
||||
|
||||
func New() *HTTPClient {
|
||||
h := httpclient.NewHttpClient().WithOptions(httpclient.Map{
|
||||
httpclient.OPT_CONNECTTIMEOUT: 5,
|
||||
httpclient.OPT_TIMEOUT: 10,
|
||||
})
|
||||
return &HTTPClient{client: h}
|
||||
}
|
||||
|
||||
func NewCtx(ctx context.Context) *HTTPClient {
|
||||
reqID, _ := ctx.Value(requestid.ContextKey).(string)
|
||||
h := httpclient.NewHttpClient().WithOptions(httpclient.Map{
|
||||
httpclient.OPT_CONNECTTIMEOUT: 5,
|
||||
httpclient.OPT_TIMEOUT: 10,
|
||||
httpclient.OPT_CONTEXT: ctx,
|
||||
}).WithHeader(requestid.HeaderKey, reqID)
|
||||
|
||||
return &HTTPClient{client: h.Begin()}
|
||||
}
|
||||
|
||||
// GetHTTPClient 获取httpclient
|
||||
func Client() *HTTPClient {
|
||||
cliID := "CLIENT-ID-"
|
||||
if len(httpCliPool.cliPool) < httpCliPool.poolSize {
|
||||
h := httpclient.NewHttpClient().Defaults(httpclient.Map{
|
||||
httpclient.OPT_CONNECTTIMEOUT: 5,
|
||||
})
|
||||
cliID = cliID + strconv.FormatInt(int64(len(httpCliPool.cliPool)+1), 10)
|
||||
httpCliPool.cliPool[cliID] = h
|
||||
httpCliPool.offset = httpCliPool.poolSize
|
||||
return &HTTPClient{client: h}
|
||||
}
|
||||
if httpCliPool.offset == httpCliPool.poolSize+1 {
|
||||
httpCliPool.offset = 1
|
||||
}
|
||||
cliID = cliID + strconv.FormatInt(int64(httpCliPool.offset), 10)
|
||||
httpCliPool.offset = httpCliPool.offset + 1
|
||||
h, ok := httpCliPool.cliPool[cliID]
|
||||
if !ok || h == nil {
|
||||
h = httpclient.NewHttpClient().WithOption(httpclient.OPT_CONNECTTIMEOUT, 10)
|
||||
httpCliPool.cliPool[cliID] = h
|
||||
return &HTTPClient{client: h}
|
||||
}
|
||||
return &HTTPClient{client: h}
|
||||
}
|
||||
|
||||
func jsonUnmarshalResp(bind interface{}, resp *HTTPResponse) error {
|
||||
if bind == nil { //传入空表示只执行 defer
|
||||
return nil
|
||||
}
|
||||
b, err := resp.Body.ReadAll()
|
||||
if err != nil {
|
||||
log.Error("httputil jsonUnmarshalResp readall err", log.E(err))
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(b, bind)
|
||||
if err != nil {
|
||||
log.Error("httputil jsonUnmarshalResp Unmarshal err", log.E(err))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Get Get方法
|
||||
func (h *HTTPClient) Get(url string, headers map[string]string, params ...interface{}) (*HTTPResponse, error) {
|
||||
h.client.WithHeaders(headers)
|
||||
response, err := h.client.Get(url, params...)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("http client Get method failed %+v:", err))
|
||||
return nil, err
|
||||
}
|
||||
return &HTTPResponse{StatusCode: response.StatusCode, Body: response}, nil
|
||||
}
|
||||
|
||||
func (h *HTTPClient) PGet(p *ProxyCfg, url string, headers map[string]string, params ...interface{}) (*HTTPResponse, error) {
|
||||
purl, pheaders, err := p.Build(url, headers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h.Get(purl, pheaders, params)
|
||||
}
|
||||
|
||||
// Get GetBytes
|
||||
func (h *HTTPClient) GetBytes(url string, headers map[string]string, params ...interface{}) ([]byte, error) {
|
||||
h.client.WithHeaders(headers)
|
||||
response, err := h.client.Get(url, params...)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("http client Get method failed %+v:", err))
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
log.Error("http client Get method status code not ok", log.Any("url", url), log.Any("headers", headers), log.Any("params", params), log.Any("res", response))
|
||||
return nil, errors.New("http response satus code not ok statusCoe:" + response.Status)
|
||||
}
|
||||
data, err := response.ReadAll()
|
||||
if err != nil {
|
||||
log.ZapLog.Error("resp readAll errror", log.Any("Error", err))
|
||||
return data, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// GetWithJResp 结果json.Unmarshal到bind中
|
||||
func (h *HTTPClient) GetWithJResp(bind interface{}, url string, headers map[string]string, params ...interface{}) (int, error) {
|
||||
resp, err := h.Get(url, headers, params...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() { _ = resp.Body.Body.Close() }()
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
err = jsonUnmarshalResp(bind, resp)
|
||||
}
|
||||
return resp.StatusCode, err
|
||||
}
|
||||
|
||||
func (h *HTTPClient) PGetWithJResp(p *ProxyCfg, bind interface{}, url string, headers map[string]string, params ...interface{}) (int, error) {
|
||||
purl, pheaders, err := p.Build(url, headers)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return h.GetWithJResp(bind, purl, pheaders, params...)
|
||||
}
|
||||
|
||||
// Post Post方法
|
||||
func (h *HTTPClient) Post(url string, headers map[string]string, params interface{}) (*HTTPResponse, error) {
|
||||
h.client.WithHeaders(headers)
|
||||
response, err := h.client.Post(url, params)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("http client Post method failed %+v:", err))
|
||||
return nil, err
|
||||
}
|
||||
return &HTTPResponse{StatusCode: response.StatusCode, Body: response}, nil
|
||||
}
|
||||
|
||||
func (h *HTTPClient) PPost(p *ProxyCfg, bind interface{}, url string, headers map[string]string, params interface{}) (*HTTPResponse, error) {
|
||||
purl, pheaders, err := p.Build(url, headers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h.Post(purl, pheaders, params)
|
||||
}
|
||||
|
||||
// POSTJson PostJson方法
|
||||
func (h *HTTPClient) POSTJson(url string, headers map[string]string, data interface{}) (*HTTPResponse, error) {
|
||||
h.client.WithHeaders(headers)
|
||||
response, err := h.client.PostJson(url, data)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("http client POSTJson method failed %+v:", err))
|
||||
return nil, err
|
||||
}
|
||||
return &HTTPResponse{StatusCode: response.StatusCode, Body: response}, nil
|
||||
}
|
||||
|
||||
// POSTJson PostJson方法, bind json.Unmarshal
|
||||
func (h *HTTPClient) POSTJsonWithJResp(bind interface{}, url string, headers map[string]string, data interface{}) (int, error) {
|
||||
resp, err := h.POSTJson(url, headers, data)
|
||||
if err != nil {
|
||||
log.Error("POSTJsonWithResp err", log.E(err))
|
||||
return 0, err
|
||||
}
|
||||
defer resp.Body.Body.Close()
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
err = jsonUnmarshalResp(bind, resp)
|
||||
}
|
||||
return resp.StatusCode, err
|
||||
}
|
||||
|
||||
func (h *HTTPClient) PPOSTJsonWithJResp(p *ProxyCfg, bind interface{}, url string, headers map[string]string, data interface{}) (int, error) {
|
||||
if p == nil {
|
||||
return 0, fmt.Errorf("ProxyCfg is nil")
|
||||
}
|
||||
purl, pheaders, err := p.Build(url, headers)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return h.POSTJsonWithJResp(bind, purl, pheaders, data)
|
||||
}
|
||||
|
||||
// PostMultipart PostMultipart 上传文件
|
||||
func (h *HTTPClient) PostMultipart(url string, headers map[string]string, params interface{}) (*HTTPResponse, error) {
|
||||
h.client.WithHeaders(headers)
|
||||
response, err := h.client.PostMultipart(url, params)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("http client PostMultipart method failed %+v:", err))
|
||||
return nil, err
|
||||
}
|
||||
return &HTTPResponse{StatusCode: response.StatusCode, Body: response}, nil
|
||||
}
|
||||
|
||||
// Put 流式传输 可用于上传文件
|
||||
func (h *HTTPClient) Put(url string, headers map[string]string, body io.Reader) (*HTTPResponse, error) {
|
||||
h.client.WithHeaders(headers)
|
||||
response, err := h.client.Put(url, body)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("http client PostMultipart method failed %+v:", err))
|
||||
return nil, err
|
||||
}
|
||||
return &HTTPResponse{StatusCode: response.StatusCode, Body: response}, nil
|
||||
}
|
||||
|
||||
// PutJSON PutJSON方法
|
||||
func (h *HTTPClient) PutJSON(url string, headers map[string]string, data interface{}) (*HTTPResponse, error) {
|
||||
h.client.WithHeaders(headers)
|
||||
response, err := h.client.PutJson(url, data)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("http client PostMultipart method failed %+v:", err))
|
||||
return nil, err
|
||||
}
|
||||
return &HTTPResponse{StatusCode: response.StatusCode, Body: response}, nil
|
||||
}
|
||||
|
||||
// Header Header
|
||||
func (h *HTTPClient) Header(url string) (*HTTPResponse, error) {
|
||||
response, err := h.client.Head(url)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("http client PostMultipart method failed %+v:", err))
|
||||
return nil, err
|
||||
}
|
||||
return &HTTPResponse{StatusCode: response.StatusCode, Body: response}, nil
|
||||
}
|
||||
|
||||
// POSTWithJResp 结果json.Unmarshal到bind中 用于上传文件, content-type :"application/x-www-form-urlencoded" 如参数以@开头 则为上传文件
|
||||
func (h *HTTPClient) POSTWithJResp(bind interface{}, url string, headers map[string]string, params interface{}) (int, error) {
|
||||
resp, err := h.Post(url, headers, params)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer resp.Body.Body.Close()
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
err = jsonUnmarshalResp(bind, resp)
|
||||
}
|
||||
return resp.StatusCode, err
|
||||
}
|
||||
|
||||
// PPOSTWithJResp 结果json.Unmarshal到bind中 用于上传文件, content-type :"application/x-www-form-urlencoded" 如参数以@开头 则为上传文件
|
||||
func (h *HTTPClient) PPOSTWithJResp(p *ProxyCfg, bind interface{}, url string, headers map[string]string, params interface{}) (int, error) {
|
||||
resp, err := h.PPost(p, bind, url, headers, params)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer resp.Body.Body.Close()
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
err = jsonUnmarshalResp(bind, resp)
|
||||
}
|
||||
return resp.StatusCode, err
|
||||
}
|
||||
Reference in New Issue
Block a user