1 Star 0 Fork 0

h79/goutils

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
http.go 10.04 KB
一键复制 编辑 原始数据 按行查看 历史
huqiuyun 提交于 2024-02-19 13:58 . log
package http
import (
"bytes"
"context"
"flag"
"fmt"
"gitee.com/h79/goutils/common/json"
"gitee.com/h79/goutils/common/logger"
"io"
"mime/multipart"
"net/http"
"net/http/httptrace"
"net/url"
"strconv"
"strings"
"sync/atomic"
"time"
)
const (
kTimeOut = time.Second * 10
KContentType = "Content-Type"
KContentDisposition = "Content-Disposition"
KContentLength = "Content-Length"
)
type HeaderFunc func(h *http.Header)
type RequestOption func(req *http.Request) (*http.Request, error)
func Method(m string) RequestOption {
return func(req *http.Request) (*http.Request, error) {
req.Method = strings.ToUpper(m)
return req, nil
}
}
var (
HEAD = Method("HEAD")
GET = Method("GET")
POST = Method("POST")
PUT = Method("PUT")
DELETE = Method("DELETE")
)
func URL(u *url.URL) RequestOption {
return func(req *http.Request) (*http.Request, error) {
req.URL = u
return req, nil
}
}
func URLString(rawUrl string) RequestOption {
return func(req *http.Request) (*http.Request, error) {
u, err := url.Parse(rawUrl)
if err != nil {
return nil, err
}
req.URL = u
return req, nil
}
}
func Path(path string) RequestOption {
return func(req *http.Request) (*http.Request, error) {
if req.URL != nil {
u, err := req.URL.Parse(path)
if err != nil {
return nil, err
}
req.URL = u
return req, nil
}
u, err := url.Parse(path)
if err != nil {
return nil, err
}
req.URL = u
return req, nil
}
}
func Params(params map[string]interface{}) RequestOption {
return func(req *http.Request) (*http.Request, error) {
u := req.URL.String()
req.URL = URLWithParams(u, params)
return req, nil
}
}
func StringParams(params map[string]string) RequestOption {
return func(req *http.Request) (*http.Request, error) {
q := req.URL.Query()
for k, v := range params {
q.Set(k, v)
}
req.URL.RawQuery = q.Encode()
return req, nil
}
}
func Body(r io.Reader) RequestOption {
return func(req *http.Request) (*http.Request, error) {
if r == nil {
req.Body = http.NoBody
req.ContentLength = 0
return req, nil
}
if rc, ok := r.(io.ReadCloser); ok {
req.Body = rc
} else {
req.Body = io.NopCloser(r)
}
if v, ok := r.(interface{ Len() int }); ok {
req.ContentLength = int64(v.Len())
} else if v, ok := r.(interface{ Size() int64 }); ok {
req.ContentLength = v.Size()
}
return req, nil
}
}
func JsonBody(body interface{}) RequestOption {
return func(req *http.Request) (*http.Request, error) {
b, err := json.DumpBytes(body)
if err != nil {
return nil, err
}
req.Body = io.NopCloser(bytes.NewBuffer(b))
req.ContentLength = int64(len(b))
req.Header.Set(KContentType, "application/json; charset=utf-8")
return req, nil
}
}
func FormBody(params map[string]interface{}) RequestOption {
return func(req *http.Request) (*http.Request, error) {
u := WithParams(params)
r := strings.NewReader(u.Encode())
req.Body = io.NopCloser(r)
req.ContentLength = int64(r.Len())
req.Header.Set(KContentType, MimeForm)
return req, nil
}
}
func Accept(ct string) RequestOption {
return func(req *http.Request) (*http.Request, error) {
req.Header.Set("Accept", ct)
return req, nil
}
}
func ContentType(ct string) RequestOption {
return func(req *http.Request) (*http.Request, error) {
req.Header.Set(KContentType, ct)
return req, nil
}
}
func ContentLength(l int64) RequestOption {
return func(req *http.Request) (*http.Request, error) {
if l >= 0 {
req.ContentLength = l
}
return req, nil
}
}
func Header(headers map[string]string) RequestOption {
return func(req *http.Request) (*http.Request, error) {
for k, v := range headers {
if strings.ToLower(k) == KContentLength {
if l, err := strconv.Atoi(v); err == nil && req.ContentLength <= 0 {
req.ContentLength = int64(l)
}
} else if v == "" {
req.Header.Del(k)
} else {
req.Header.Set(k, v)
}
}
return req, nil
}
}
func Context(ctx context.Context) RequestOption {
return func(req *http.Request) (*http.Request, error) {
return req.WithContext(ctx), nil
}
}
func Trace(tracer *httptrace.ClientTrace) RequestOption {
return func(req *http.Request) (*http.Request, error) {
return req.WithContext(httptrace.WithClientTrace(req.Context(), tracer)), nil
}
}
// Response 请求回应
type Response struct {
StatusCode int
contentDisposition string
contentType string
contentLength int64
body []byte
}
func (res *Response) GetContentDisposition() string {
return res.contentDisposition
}
func (res *Response) IsFile() bool {
return strings.HasPrefix(res.contentDisposition, "attachment;")
}
func (res *Response) FileName() string {
filename := strings.TrimPrefix(res.contentDisposition, "attachment;")
filename = strings.TrimPrefix(filename, " ")
if strings.HasPrefix(filename, "filename=") {
filename = strings.TrimPrefix(filename, "filename=")
}
filename = strings.TrimPrefix(filename, "\"")
filename = strings.TrimSuffix(filename, "\"")
f := strings.Split(filename, "/")
if len(f) > 0 {
filename = f[len(f)-1]
}
if filename == "*" {
filename = ""
}
return filename
}
func (res *Response) GetContentLength() int64 {
return res.contentLength
}
func (res *Response) GetContentType() string {
return res.contentType
}
func (res *Response) GetBody() []byte {
return res.body
}
func (res *Response) Reset() {
res.contentLength = 0
res.contentType = ""
res.contentDisposition = ""
res.body = []byte{}
}
var EnableLog bool = true
func init() {
flag.BoolVar(&EnableLog, "httpLog", true, "http log")
}
type NewHttpClientFunc func(h *Http, timeout time.Duration) *http.Client
var defaultNewHttpClient = func(h *Http, timeout time.Duration) *http.Client {
return &http.Client{
Timeout: timeout,
}
}
//Http
type Http struct {
DisableLog bool
SeqNo string
TimeOut time.Duration
newClient NewHttpClientFunc
response Response
}
func (hp *Http) SetNewHttpClient(fn NewHttpClientFunc) {
hp.newClient = fn
}
func (hp *Http) LogEnabled() bool {
return !hp.DisableLog && EnableLog
}
func (hp *Http) GetResponse() *Response {
return &hp.response
}
func (hp *Http) WithTimeout(duration time.Duration) *Http {
hp.TimeOut = duration
return hp
}
func (hp *Http) DoString(method string, url string, buf []byte, reqOpts ...RequestOption) (string, error) {
ret, err := hp.DoBytes(method, url, buf, reqOpts...)
if err != nil {
return "", err
}
return string(ret), nil
}
func (hp *Http) DoBytes(method string, url string, buf []byte, reqOpts ...RequestOption) ([]byte, error) {
return hp.DoWithHead(method, url, buf, nil, reqOpts...)
}
func (hp *Http) DoWithHead(method string, url string, buf []byte, headerFunc HeaderFunc, reqOpts ...RequestOption) ([]byte, error) {
body, err := hp.Do(method, url, bytes.NewBuffer(buf), func(h *http.Header) {
h.Set(KContentType, MimeJSONUtf8)
if headerFunc != nil {
headerFunc(h)
}
}, reqOpts...)
if err != nil {
return nil, err
}
return body, nil
}
func (hp *Http) DoMultiForm(url string, reqOpts ...RequestOption) ([]byte, error) {
sp := strings.SplitN(url, "?", 2)
if len(sp) <= 1 {
return hp.DoFormWith(sp[0], "")
}
return hp.DoFormWith(sp[0], sp[1], reqOpts...)
}
func (hp *Http) DoMultiFormWith(rawUrl, query string, reqOpts ...RequestOption) ([]byte, error) {
val, er := url.ParseQuery(query)
if er != nil {
return nil, er
}
return hp.DoMultiFormWithValues(rawUrl, val, reqOpts...)
}
func (hp *Http) DoMultiFormWithValues(url string, form url.Values, reqOpts ...RequestOption) ([]byte, error) {
body := new(bytes.Buffer)
w := multipart.NewWriter(body)
for k, v := range form {
_ = w.WriteField(k, v[0])
}
_ = w.Close()
return hp.Do("POST", url, body, func(h *http.Header) {
h.Set(KContentType, w.FormDataContentType())
}, reqOpts...)
}
// DoForm
// url http://api.xxx.com/ssddd?key=ddd&ddd=sfsf
func (hp *Http) DoForm(url string, reqOpts ...RequestOption) ([]byte, error) {
sp := strings.SplitN(url, "?", 2)
if len(sp) <= 1 {
return hp.DoFormWith(sp[0], "")
}
return hp.DoFormWith(sp[0], sp[1], reqOpts...)
}
// DoFormWith
// query ssddd=sdsfs&sfssfs=sfsssfs&sfsfsfs&
func (hp *Http) DoFormWith(rawUrl, query string, reqOpts ...RequestOption) ([]byte, error) {
val, er := url.ParseQuery(query)
if er != nil {
return nil, er
}
return hp.DoFormWithValues(rawUrl, val, reqOpts...)
}
func (hp *Http) DoFormWithValues(url string, values url.Values, reqOpts ...RequestOption) ([]byte, error) {
return hp.Do("POST", url, strings.NewReader(values.Encode()), func(h *http.Header) {
h.Set(KContentType, MimeForm)
}, reqOpts...)
}
var httpNo = int64(0)
func (hp *Http) Do(method string, url string, body io.Reader, headerFunc HeaderFunc, reqOpts ...RequestOption) ([]byte, error) {
var no = httpNo
if hp.LogEnabled() {
no = atomic.AddInt64(&httpNo, 1)
logger.N("Http", "REQ method= '%s', seqNo= '%s', no= '%d', url= '%s'", method, hp.SeqNo, no, url)
}
hp.response.Reset()
hp.response.StatusCode = 200
// Now that you have a form, you can submit it to your handler.
req, err := http.NewRequest(method, url, body)
if err != nil {
fmt.Printf("Http:Do url= '%s', err= '%s',", url, err)
return nil, err
}
if headerFunc != nil {
headerFunc(&req.Header)
}
for i := range reqOpts {
req, err = reqOpts[i](req)
if err != nil {
return nil, err
}
}
timeout := kTimeOut
if hp.TimeOut > 0 {
timeout = time.Second * hp.TimeOut
}
var fn = hp.newClient
if fn == nil {
fn = defaultNewHttpClient
}
// Submit the request
client := fn(hp, timeout)
res, err := client.Do(req)
if err != nil {
fmt.Printf("Http:Do url= '%s', err= '%s',", url, err)
return nil, err
}
defer res.Body.Close()
hp.response.StatusCode = res.StatusCode
hp.response.contentDisposition = res.Header.Get(KContentDisposition)
hp.response.contentType = res.Header.Get(KContentType)
hp.response.contentLength = res.ContentLength
hp.response.body, err = io.ReadAll(res.Body)
if hp.LogEnabled() {
logger.N("Http", "RESP httpStatus= %d, seqNo= '%s', no= '%d', body= '%s', err= '%v'", res.StatusCode, hp.SeqNo, no, logger.Byte2(logger.NDebugLevel, hp.response.body), err)
}
return hp.response.body, err
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/h79/goutils.git
git@gitee.com:h79/goutils.git
h79
goutils
goutils
v1.20.67

搜索帮助