提交 a24f8839 authored 作者: mooncake9527's avatar mooncake9527

update

上级 da9c0e3b
...@@ -14,58 +14,51 @@ import ( ...@@ -14,58 +14,51 @@ import (
"strings" "strings"
"time" "time"
"github.com/duke-git/lancet/v2/retry"
"gitlab.wanzhuangkj.com/tush/xpkg/gin/ctxUtils" "gitlab.wanzhuangkj.com/tush/xpkg/gin/ctxUtils"
"gitlab.wanzhuangkj.com/tush/xpkg/logger" "gitlab.wanzhuangkj.com/tush/xpkg/logger"
"gitlab.wanzhuangkj.com/tush/xpkg/utils/xjson"
"gitlab.wanzhuangkj.com/tush/xpkg/xerrors/xerror"
"github.com/duke-git/lancet/v2/retry"
) )
const defaultTimeout = 30 * time.Second const defaultTimeout = 30 * time.Second
var (
contentMark = []byte(" ...... ")
)
// Request HTTP request
type Request struct { type Request struct {
customRequest func(req *http.Request, data *bytes.Buffer) // used to define HEADER, e.g. to add sign, etc.
url string url string
method string
headers map[string]string
params map[string]interface{} // parameters after URL params map[string]interface{} // parameters after URL
body string // Body data reqBody []byte // Body data
bodyJSON interface{} // JSON marshal body data reqBodyJSON interface{} // 传入对象,会自动json marshal
timeout time.Duration // Client timeout timeout time.Duration // Client timeout
retryCount uint retryCount uint
headers map[string]string
rspBody []byte
request *http.Request request *http.Request
response *Response response *Response
method string
err error err error
} }
// Response HTTP response // Response HTTP response
type Response struct { type Response struct {
Body io.ReadCloser //Body io.ReadCloser
StatusCode int StatusCode int
Status string // e.g. "200 OK" Status string
Header http.Header Header http.Header
err error
} }
// ----------------------------------- Request way 1 ----------------------------------- // ----------------------------------- Request way 1 -----------------------------------
// New create a new Request // New create a new Request
func New() *Request { func New() *Request {
return &Request{} return &Request{
response: &Response{},
}
} }
// Reset set all fields to default value, use at pool // Reset set all fields to default value, use at pool
func (req *Request) Reset() { func (req *Request) Reset() {
req.params = nil req.params = nil
req.body = "" req.reqBody = nil
req.bodyJSON = nil req.reqBodyJSON = nil
req.timeout = 0 req.timeout = 0
req.headers = nil req.headers = nil
...@@ -106,11 +99,11 @@ func (req *Request) SetParam(k string, v interface{}) *Request { ...@@ -106,11 +99,11 @@ func (req *Request) SetParam(k string, v interface{}) *Request {
func (req *Request) SetBody(body interface{}) *Request { func (req *Request) SetBody(body interface{}) *Request {
switch v := body.(type) { switch v := body.(type) {
case string: case string:
req.body = v req.reqBody = []byte(v)
case []byte: case []byte:
req.body = string(v) req.reqBody = v
default: default:
req.bodyJSON = body req.reqBodyJSON = body
} }
return req return req
} }
...@@ -151,46 +144,44 @@ func (req *Request) SetHeaders(headers map[string]string) *Request { ...@@ -151,46 +144,44 @@ func (req *Request) SetHeaders(headers map[string]string) *Request {
return req return req
} }
// CustomRequest customize request, e.g. add sign, set header, etc.
func (req *Request) CustomRequest(f func(req *http.Request, data *bytes.Buffer)) *Request {
req.customRequest = f
return req
}
// GET send a GET request // GET send a GET request
func (req *Request) GET(ctx context.Context) (*Response, error) { func (req *Request) GET(ctx context.Context) *Request {
req.method = http.MethodGet req.method = http.MethodGet
return req.pull(ctx) req.pull(ctx)
return req
} }
// DELETE send a DELETE request // DELETE send a DELETE request
func (req *Request) DELETE(ctx context.Context) (*Response, error) { func (req *Request) DELETE(ctx context.Context) *Request {
req.method = http.MethodDelete req.method = http.MethodDelete
return req.pull(ctx) req.pull(ctx)
return req
} }
// POST send a POST request // POST send a POST request
func (req *Request) POST(ctx context.Context) (*Response, error) { func (req *Request) POST(ctx context.Context) *Request {
req.method = http.MethodPost req.method = http.MethodPost
return req.push(ctx) req.push(ctx)
return req
} }
// PUT send a PUT request // PUT send a PUT request
func (req *Request) PUT(ctx context.Context) (*Response, error) { func (req *Request) PUT(ctx context.Context) *Request {
req.method = http.MethodPut req.method = http.MethodPut
return req.push(ctx) req.push(ctx)
return req
} }
// PATCH send PATCH requests // PATCH send PATCH requests
func (req *Request) PATCH(ctx context.Context) (*Response, error) { func (req *Request) PATCH(ctx context.Context) *Request {
req.method = http.MethodPatch req.method = http.MethodPatch
return req.push(ctx) req.push(ctx)
return req
} }
// Do a request // Do a request
func (req *Request) Do(ctx context.Context, method string, data interface{}) (*Response, error) { func (req *Request) Do(ctx context.Context, method string, data interface{}) *Request {
req.method = method req.method = method
switch method { switch method {
case http.MethodGet, http.MethodDelete: case http.MethodGet, http.MethodDelete:
if data != nil { if data != nil {
...@@ -198,25 +189,22 @@ func (req *Request) Do(ctx context.Context, method string, data interface{}) (*R ...@@ -198,25 +189,22 @@ func (req *Request) Do(ctx context.Context, method string, data interface{}) (*R
req.SetParams(params) req.SetParams(params)
} else { } else {
req.err = errors.New("params is not a map[string]interface{}") req.err = errors.New("params is not a map[string]interface{}")
return nil, req.err return req
} }
} }
req.pull(ctx)
return req.pull(ctx)
case http.MethodPost, http.MethodPut, http.MethodPatch: case http.MethodPost, http.MethodPut, http.MethodPatch:
if data != nil { if data != nil {
req.SetBody(data) req.SetBody(data)
} }
req.push(ctx)
return req.push(ctx) default:
}
req.err = errors.New("unknow method " + method) req.err = errors.New("unknow method " + method)
return nil, req.err }
return req
} }
func (req *Request) pull(ctx context.Context) (*Response, error) { func (req *Request) pull(ctx context.Context) {
val := "" val := ""
if len(req.params) > 0 { if len(req.params) > 0 {
values := url.Values{} values := url.Values{}
...@@ -233,44 +221,31 @@ func (req *Request) pull(ctx context.Context) (*Response, error) { ...@@ -233,44 +221,31 @@ func (req *Request) pull(ctx context.Context) (*Response, error) {
req.url += "?" + val req.url += "?" + val
} }
} }
req.send(ctx)
var buf *bytes.Buffer
if req.customRequest != nil {
buf = bytes.NewBufferString(val)
}
return req.send(ctx, nil, buf)
} }
func (req *Request) push(ctx context.Context) (*Response, error) { func (req *Request) push(ctx context.Context) {
var buf *bytes.Buffer if req.reqBodyJSON != nil {
body, err := json.Marshal(req.reqBodyJSON)
if req.bodyJSON != nil {
body, err := json.Marshal(req.bodyJSON)
if err != nil { if err != nil {
req.err = err req.err = err
return nil, req.err return
} }
buf = bytes.NewBuffer(body) req.reqBody = body
} else {
buf = bytes.NewBufferString(req.body)
} }
req.send(ctx)
return req.send(ctx, buf, buf)
} }
func (req *Request) send(ctx context.Context, body io.Reader, buf *bytes.Buffer) (*Response, error) { func (req *Request) send(ctx context.Context) {
req.request, req.err = http.NewRequest(req.method, req.url, body) bodyBuf := bytes.NewBuffer(req.reqBody)
req.request, req.err = http.NewRequest(req.method, req.url, bodyBuf)
if req.err != nil { if req.err != nil {
return nil, req.err return
} }
if buf != nil { if req.reqBody != nil {
if c, _ := ctxUtils.GetGinCtx(ctx); c != nil { if c, _ := ctxUtils.GetGinCtx(ctx); c != nil {
entity.SetCopyApiReq(c, buf) entity.SetCopyApiReq(c, bodyBuf)
}
} }
if req.customRequest != nil {
req.customRequest(req.request, buf)
} }
if req.headers != nil { if req.headers != nil {
for k, v := range req.headers { for k, v := range req.headers {
...@@ -286,195 +261,104 @@ func (req *Request) send(ctx context.Context, body io.Reader, buf *bytes.Buffer) ...@@ -286,195 +261,104 @@ func (req *Request) send(ctx context.Context, body io.Reader, buf *bytes.Buffer)
logger.Any("method", req.method), logger.Any("method", req.method),
logger.Any("url", req.url), logger.Any("url", req.url),
logger.Any("header", req.request.Header), logger.Any("header", req.request.Header),
logger.Any("body", buf.String()), logger.Any("body", bodyBuf.String()),
ctxUtils.CtxTraceIDField(ctx)) ctxUtils.CtxTraceIDField(ctx))
client := http.Client{Timeout: req.timeout}
resp := &Response{
Header: make(http.Header),
}
ctx, cancel := context.WithTimeout(ctx, time.Second*20)
defer cancel()
var err error
if req.retryCount > 0 { if req.retryCount > 0 {
err = retry.Retry(func() error { _ = retry.Retry(func() error {
response, err := client.Do(req.request) req.pushDo(ctx)
if err != nil { return req.err
logger.Info("[httpCli] fail", logger.Any("err", err), ctxUtils.CtxTraceIDField(ctx))
return xerror.Wrap(err, "client do")
}
if response != nil {
resp.Status = response.Status
resp.StatusCode = response.StatusCode
for k, v := range response.Header {
resp.Header[k] = append(resp.Header[k], v...)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
return xerror.Wrap(err, "read response body")
}
bodyBuf := bytes.NewBuffer(body)
if c, _ := ctxUtils.GetGinCtx(ctx); c != nil {
entity.SetCopyApiRsp(c, buf)
}
logger.Info("[httpCli] rsp",
logger.Any("header", resp.Header),
logger.Any("body", bodyBuf.String()),
ctxUtils.CtxTraceIDField(ctx))
if body != nil {
resp.Body = io.NopCloser(bodyBuf)
}
}
return nil
}, },
retry.RetryTimes(req.retryCount), retry.RetryTimes(req.retryCount),
retry.RetryWithLinearBackoff(2*time.Second), retry.RetryWithLinearBackoff(8*time.Second),
retry.Context(ctx), retry.Context(ctx),
) )
} else { } else {
response, e := client.Do(req.request) req.pushDo(ctx)
if e != nil {
err = xerror.New(e.Error())
if response != nil {
resp.Status = response.Status
resp.StatusCode = response.StatusCode
for k, v := range response.Header {
resp.Header[k] = append(resp.Header[k], v...)
}
resp.err = err
} }
return resp, err
} var rspHeader map[string][]string
if response != nil { var rspBodyStr string
resp.Status = response.Status if req.response != nil {
resp.StatusCode = response.StatusCode rspHeader = req.response.Header
for k, v := range response.Header { if len(req.rspBody) > 0 {
resp.Header[k] = append(resp.Header[k], v...) rspBodyStr = bytes.NewBuffer(req.rspBody).String()
} }
defer response.Body.Close()
body, e := io.ReadAll(response.Body)
if e != nil {
err = xerror.New(e.Error())
} }
bodyBuf := bytes.NewBuffer(body)
logger.Info("[httpCli] rsp", logger.Info("[httpCli] rsp",
logger.Any("header", resp.Header), logger.Any("method", req.method),
logger.Any("body", bodyBuf.String()), logger.Any("status", req.response.Status),
logger.Any("url", req.url),
logger.Any("header", rspHeader),
logger.Any("body", rspBodyStr),
ctxUtils.CtxTraceIDField(ctx)) ctxUtils.CtxTraceIDField(ctx))
if c, _ := ctxUtils.GetGinCtx(ctx); c != nil {
entity.SetCopyApiRsp(c, bodyBuf)
}
if body != nil {
resp.Body = io.NopCloser(bodyBuf)
}
}
}
if err != nil {
logger.Error("[httpCli] fail", logger.Any("err", err), ctxUtils.CtxTraceIDField(ctx))
}
ctxUtils.SetApiCost(ctx, resp.Header)
req.response = resp
req.err = err
resp.err = err
return resp, resp.err
} }
func copyResponse(resp *Response, response *http.Response) { func (req *Request) pushDo(ctx context.Context) {
if resp == nil || response == nil { client := http.Client{Timeout: req.timeout}
ctx, cancel := context.WithTimeout(ctx, req.timeout)
defer cancel()
response, e := client.Do(req.request)
if e != nil {
req.err = e
return return
} }
resp.Status = response.Status if response != nil {
resp.StatusCode = response.StatusCode req.response.Status = response.Status
for k, v := range response.Header { req.response.Header = response.Header
resp.Header[k] = append(resp.Header[k], v...) ctxUtils.SetApiCost(ctx, req.response.Header)
} req.response.StatusCode = response.StatusCode
if response.Body != nil { if response.Body != nil {
defer response.Body.Close() defer response.Body.Close()
body, err := io.ReadAll(response.Body) req.rspBody, req.err = io.ReadAll(response.Body)
if err != nil { if req.err != nil {
resp.err = xerror.Wrap(err, "read response body") return
} }
if len(body) > 0 { if len(req.rspBody) > 0 {
resp.Body = io.NopCloser(bytes.NewBuffer(body)) if c, _ := ctxUtils.GetGinCtx(ctx); c != nil {
entity.SetCopyApiRsp(c, bytes.NewBuffer(req.rspBody))
}
//req.response.Body = io.NopCloser(bytes.NewBuffer(req.rspBody))
} }
} }
}
// Response return response
func (req *Request) Response() (*Response, error) {
if req.err != nil {
return nil, req.err
} }
return req.response, req.response.Error()
} }
// ----------------------------------- Response ----------------------------------- // ----------------------------------- Response -----------------------------------
// Error return err func (req *Request) Err() error {
func (resp *Response) Error() error { return req.err
return resp.err
}
// BodyString returns the body data of the HttpResponse
func (resp *Response) BodyString() (string, error) {
if resp.err != nil {
return "", resp.err
}
body, err := resp.ReadBody()
return string(body), err
} }
// BodyString returns the body data of the HttpResponse // BodyString returns the body data of the HttpResponse
func (resp *Response) RspString() string { func (req *Request) BodyString() string {
ret := make(map[string]any) if len(req.rspBody) == 0 {
ret["status"] = resp.Status return ""
ret["statusCode"] = resp.StatusCode
ret["header"] = resp.Header
if resp.err != nil {
ret["err"] = resp.err.Error()
} }
body, err := resp.ReadBody() return string(req.rspBody)
if err == nil {
ret["body"] = bytes.NewBuffer(body).String()
}
return xjson.ToJsonString(ret)
} }
// ReadBody returns the body data of the HttpResponse func (req *Request) ReadRspBody() ([]byte, error) {
func (resp *Response) ReadBody() ([]byte, error) { if req.err != nil {
if resp.err != nil { return []byte{}, req.err
return []byte{}, resp.err
} }
if resp.Body == nil { if req.rspBody == nil {
return []byte{}, errors.New("nil") return []byte{}, errors.New("nil")
} }
body, err := io.ReadAll(resp.Body) return req.rspBody, nil
if err != nil {
return []byte{}, err
}
resp.Body.Close()
resp.Body = io.NopCloser(bytes.NewBuffer(body))
return body, nil
} }
// BindJSON parses the response's body as JSON // BindJSON parses the response's body as JSON
func (resp *Response) BindJSON(v interface{}) error { func (req *Request) BindJSON(v interface{}) *Request {
if resp.err != nil { if req.err != nil {
return resp.err return req
} }
body, err := resp.ReadBody() if err := json.Unmarshal(req.rspBody, v); err != nil {
if err != nil { req.err = err
return err
} }
return json.Unmarshal(body, v) return req
} }
// ----------------------------------- Request way 2 ----------------------------------- // ----------------------------------- Request way 2 -----------------------------------
...@@ -519,125 +403,127 @@ func WithTimeout(t time.Duration) Option { ...@@ -519,125 +403,127 @@ func WithTimeout(t time.Duration) Option {
} }
} }
// Get request, return custom json format //
func Get(ctx context.Context, result interface{}, urlStr string, opts ...Option) error { //// Get request, return custom json format
o := defaultOptions() //func Get(ctx context.Context, result interface{}, urlStr string, opts ...Option) error {
o.apply(opts...) // o := defaultOptions()
return gDo(ctx, "GET", result, urlStr, o.params, o.headers, o.timeout) // o.apply(opts...)
} // return gDo(ctx, "GET", result, urlStr, o.params, o.headers, o.timeout)
//}
// Delete request, return custom json format //
func Delete(ctx context.Context, result interface{}, urlStr string, opts ...Option) error { //// Delete request, return custom json format
o := defaultOptions() //func Delete(ctx context.Context, result interface{}, urlStr string, opts ...Option) error {
o.apply(opts...) // o := defaultOptions()
return gDo(ctx, "DELETE", result, urlStr, o.params, o.headers, o.timeout) // o.apply(opts...)
} // return gDo(ctx, "DELETE", result, urlStr, o.params, o.headers, o.timeout)
//}
// Post request, return custom json format //
func Post(ctx context.Context, result interface{}, urlStr string, body interface{}, opts ...Option) error { //// Post request, return custom json format
o := defaultOptions() //func Post(ctx context.Context, result interface{}, urlStr string, body interface{}, opts ...Option) error {
o.apply(opts...) // o := defaultOptions()
return do(ctx, "POST", result, urlStr, body, o.params, o.headers, o.timeout) // o.apply(opts...)
} // return do(ctx, "POST", result, urlStr, body, o.params, o.headers, o.timeout)
//}
// Put request, return custom json format //
func Put(ctx context.Context, result interface{}, urlStr string, body interface{}, opts ...Option) error { //// Put request, return custom json format
o := defaultOptions() //func Put(ctx context.Context, result interface{}, urlStr string, body interface{}, opts ...Option) error {
o.apply(opts...) // o := defaultOptions()
return do(ctx, "PUT", result, urlStr, body, o.params, o.headers, o.timeout) // o.apply(opts...)
} // return do(ctx, "PUT", result, urlStr, body, o.params, o.headers, o.timeout)
//}
// Patch request, return custom json format //
func Patch(ctx context.Context, result interface{}, urlStr string, body interface{}, opts ...Option) error { //// Patch request, return custom json format
o := defaultOptions() //func Patch(ctx context.Context, result interface{}, urlStr string, body interface{}, opts ...Option) error {
o.apply(opts...) // o := defaultOptions()
return do(ctx, "PATCH", result, urlStr, body, o.params, o.headers, o.timeout) // o.apply(opts...)
} // return do(ctx, "PATCH", result, urlStr, body, o.params, o.headers, o.timeout)
//}
var requestErr = func(err error) error { return fmt.Errorf("request error, err=%v", err) } //
var jsonParseErr = func(err error) error { return fmt.Errorf("json parsing error, err=%v", err) } //var requestErr = func(err error) error { return fmt.Errorf("request error, err=%v", err) }
var notOKErr = func(resp *Response) error { //var jsonParseErr = func(err error) error { return fmt.Errorf("json parsing error, err=%v", err) }
body, err := resp.ReadBody() //var notOKErr = func(resp *Response) error {
if err != nil { // body, err := resp.ReadBody()
return err // if err != nil {
} // return err
if len(body) > 500 { // }
body = append(body[:500], []byte(" ......")...) // if len(body) > 500 {
} // body = append(body[:500], []byte(" ......")...)
return fmt.Errorf("statusCode=%d, body=%s", resp.StatusCode, body) // }
} // return fmt.Errorf("statusCode=%d, body=%s", resp.StatusCode, body)
//}
func do(ctx context.Context, method string, result interface{}, urlStr string, body interface{}, params KV, headers map[string]string, timeout time.Duration) error { //
if result == nil { //func do(ctx context.Context, method string, result interface{}, urlStr string, body interface{}, params KV, headers map[string]string, timeout time.Duration) error {
return fmt.Errorf("'result' can not be nil") // if result == nil {
} // return fmt.Errorf("'result' can not be nil")
// }
req := &Request{} //
req.SetURL(urlStr) // req := &Request{}
req.SetContentType("application/json") // req.SetURL(urlStr)
req.SetParams(params) // req.SetContentType("application/json")
req.SetHeaders(headers) // req.SetParams(params)
req.SetBody(body) // req.SetHeaders(headers)
req.SetTimeout(timeout) // req.SetBody(body)
// req.SetTimeout(timeout)
var resp *Response //
var err error // var resp *Response
switch method { // var err error
case "POST": // switch method {
resp, err = req.POST(ctx) // case "POST":
case "PUT": // resp, err = req.POST(ctx)
resp, err = req.PUT(ctx) // case "PUT":
case "PATCH": // resp, err = req.PUT(ctx)
resp, err = req.PATCH(ctx) // case "PATCH":
} // resp, err = req.PATCH(ctx)
if err != nil { // }
return requestErr(err) // if err != nil {
} // return requestErr(err)
defer resp.Body.Close() //nolint // }
// defer resp.Body.Close() //nolint
if resp.StatusCode != 200 { //
return notOKErr(resp) // if resp.StatusCode != 200 {
} // return notOKErr(resp)
// }
err = resp.BindJSON(result) //
if err != nil { // err = resp.BindJSON(result)
return jsonParseErr(err) // if err != nil {
} // return jsonParseErr(err)
// }
return nil //
} // return nil
//}
func gDo(ctx context.Context, method string, result interface{}, urlStr string, params KV, headers map[string]string, timeout time.Duration) error {
req := &Request{} //
req.SetURL(urlStr) //func gDo(ctx context.Context, method string, result interface{}, urlStr string, params KV, headers map[string]string, timeout time.Duration) error {
req.SetParams(params) // req := &Request{}
req.SetHeaders(headers) // req.SetURL(urlStr)
req.SetTimeout(timeout) // req.SetParams(params)
// req.SetHeaders(headers)
var resp *Response // req.SetTimeout(timeout)
var err error //
switch method { // var resp *Response
case "GET": // var err error
resp, err = req.GET(ctx) // switch method {
case "DELETE": // case "GET":
resp, err = req.DELETE(ctx) // resp, err = req.GET(ctx)
} // case "DELETE":
if err != nil { // resp, err = req.DELETE(ctx)
return requestErr(err) // }
} // if err != nil {
defer resp.Body.Close() //nolint // return requestErr(err)
// }
if resp.StatusCode != 200 { // defer resp.Body.Close() //nolint
return notOKErr(resp) //
} // if resp.StatusCode != 200 {
// return notOKErr(resp)
err = resp.BindJSON(result) // }
if err != nil { //
return jsonParseErr(err) // err = resp.BindJSON(result)
} // if err != nil {
// return jsonParseErr(err)
return nil // }
} //
// return nil
//}
// StdResult standard return data // StdResult standard return data
type StdResult struct { type StdResult struct {
......
package httpcli package httpcli
import ( import (
"bytes"
"context" "context"
"errors"
"fmt"
"net/http"
"testing" "testing"
"time"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"gitlab.wanzhuangkj.com/tush/xpkg/utils"
) )
type myBody struct { func TestRequest_SetBody(t *testing.T) {
Name string `json:"name"` ctx := context.Background()
Email string `json:"email"`
}
func runGoHTTPServer() string {
serverAddr, requestAddr := utils.GetLocalHTTPAddrPairs()
gin.SetMode(gin.ReleaseMode)
r := gin.Default()
oKFun := func(c *gin.Context) {
uid := c.Query("uid")
fmt.Printf("request parameters: uid=%s\n", uid)
c.JSON(200, StdResult{
Code: 0,
Msg: "ok",
Data: fmt.Sprintf("uid=%v", uid),
})
}
errFun := func(c *gin.Context) {
uid := c.Query("uid")
fmt.Printf("request parameters: uid=%s\n", uid)
c.JSON(401, StdResult{
Code: 401,
Msg: "authorization failure",
Data: fmt.Sprintf("uid=%v", uid),
})
}
oKPFun := func(c *gin.Context) {
var body myBody
c.BindJSON(&body)
fmt.Println("body data:", body)
c.JSON(200, StdResult{
Code: 0,
Msg: "ok",
Data: body,
})
}
errPFun := func(c *gin.Context) {
var body myBody
c.BindJSON(&body)
fmt.Println("body data:", body)
c.JSON(401, StdResult{
Code: 401,
Msg: "authorization failure",
Data: nil,
})
}
r.GET("/get", oKFun)
r.GET("/get_err", errFun)
r.DELETE("/delete", oKFun)
r.DELETE("/delete_err", errFun)
r.POST("/post", oKPFun)
r.POST("/post_err", errPFun)
r.PUT("/put", oKPFun)
r.PUT("/put_err", errPFun)
r.PATCH("/patch", oKPFun)
r.PATCH("/patch_err", errPFun)
go func() {
err := r.Run(serverAddr)
if err != nil {
panic(err)
}
}()
time.Sleep(time.Millisecond * 200)
return requestAddr
}
// ------------------------------------------------------------------------------------------
func TestGetStandard(t *testing.T) {
requestAddr := runGoHTTPServer()
req := New() req := New()
req.SetURL(requestAddr + "/get") ret := make(map[string]any)
req.SetHeaders(map[string]string{ if err := req.SetURL("http://baidu.com").
"Authorization": "Bearer token", SetParams(KV{"a": "b"}).
}) GET(ctx).
req.SetParams(KV{ BindJSON(&ret).
"name": "foo", Err(); err != nil {
}) t.Error(err.Error())
resp, err := req.GET(context.Background())
if err != nil {
t.Fatal(err)
}
result := &StdResult{}
err = resp.BindJSON(result)
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", result)
}
func TestDeleteStandard(t *testing.T) {
requestAddr := runGoHTTPServer()
req := New()
req.SetURL(requestAddr + "/delete")
req.SetHeaders(map[string]string{
"Authorization": "Bearer token",
})
req.SetParams(KV{
"uid": 123,
})
resp, err := req.DELETE(context.Background())
if err != nil {
t.Fatal(err)
}
result := &StdResult{}
err = resp.BindJSON(result)
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", result)
}
func TestPostStandard(t *testing.T) {
requestAddr := runGoHTTPServer()
req := New()
req.SetURL(requestAddr + "/post")
req.SetHeaders(map[string]string{
"Authorization": "Bearer token",
})
req.SetBody(&myBody{
Name: "foo",
Email: "bar@gmail.com",
})
resp, err := req.POST(context.Background())
if err != nil {
t.Fatal(err)
}
result := &StdResult{}
err = resp.BindJSON(result)
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", result)
}
func TestPutStandard(t *testing.T) {
requestAddr := runGoHTTPServer()
req := New()
req.SetURL(requestAddr + "/put")
req.SetHeaders(map[string]string{
"Authorization": "Bearer token",
})
req.SetBody(&myBody{
Name: "foo",
Email: "bar@gmail.com",
})
resp, err := req.PUT(context.Background())
if err != nil {
t.Fatal(err)
}
result := &StdResult{}
err = resp.BindJSON(result)
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", result)
}
func TestPatchStandard(t *testing.T) {
requestAddr := runGoHTTPServer()
req := New()
req.SetURL(requestAddr + "/patch")
req.SetHeaders(map[string]string{
"Authorization": "Bearer token",
})
req.SetBody(&myBody{
Name: "foo",
Email: "bar@gmail.com",
})
resp, err := req.PATCH(context.Background())
if err != nil {
t.Fatal(err)
}
result := &StdResult{}
err = resp.BindJSON(result)
if err != nil {
t.Fatal(err)
}
t.Logf("%+v", result)
}
// ------------------------------------------------------------------------------------------
func TestGet(t *testing.T) {
requestAddr := runGoHTTPServer()
type args struct {
result interface{}
url string
params map[string]interface{}
headers map[string]string
}
tests := []struct {
name string
args args
wantErr bool
wantResult *StdResult
}{
{
name: "get success",
args: args{
result: &StdResult{},
url: requestAddr + "/get",
params: KV{"uid": 123},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantErr: false,
wantResult: &StdResult{
Code: 0,
Msg: "ok",
Data: "uid=123",
},
},
{
name: "get err",
args: args{
result: &StdResult{},
url: requestAddr + "/get_err",
params: KV{"uid": 123},
},
wantErr: true,
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
},
{
name: "get not found",
args: args{
result: &StdResult{},
url: requestAddr + "/notfound",
},
wantErr: true,
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := Get(context.Background(), tt.args.result, tt.args.url, WithParams(tt.args.params), WithHeaders(tt.args.headers))
if (err != nil) != tt.wantErr {
t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.args.result.(*StdResult).Msg != tt.wantResult.Msg {
t.Errorf("gotResult = %v, wantResult = %v", tt.args.result, tt.wantResult)
} }
})
}
}
func TestDelete(t *testing.T) {
requestAddr := runGoHTTPServer()
type args struct {
result interface{}
url string
params KV
headers map[string]string
}
tests := []struct {
name string
args args
wantErr bool
wantResult *StdResult
}{
{
name: "delete success",
args: args{
result: &StdResult{},
url: requestAddr + "/delete",
params: KV{"uid": 123},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantErr: false,
wantResult: &StdResult{
Code: 0,
Msg: "ok",
Data: "uid=123",
},
},
{
name: "delete err",
args: args{
result: &StdResult{},
url: requestAddr + "/delete_err",
params: KV{"uid": 123},
},
wantErr: true,
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
},
{
name: "delete not found",
args: args{
result: &StdResult{},
url: requestAddr + "/notfound",
},
wantErr: true,
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := Delete(context.Background(), tt.args.result, tt.args.url, WithParams(tt.args.params), WithHeaders(tt.args.headers))
if (err != nil) != tt.wantErr {
t.Errorf("Delete() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.args.result.(*StdResult).Msg != tt.wantResult.Msg {
t.Errorf("gotResult = %v, wantResult = %v", tt.args.result, tt.wantResult)
}
})
}
}
func TestPost(t *testing.T) {
requestAddr := runGoHTTPServer()
type args struct {
result interface{}
url string
body interface{}
headers map[string]string
timeout time.Duration
}
tests := []struct {
name string
args args
wantResult *StdResult
wantErr bool
}{
{
name: "post success",
args: args{
result: &StdResult{},
url: requestAddr + "/post",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
headers: map[string]string{
"Authorization": "Bearer token",
},
timeout: time.Second,
},
wantResult: &StdResult{
Code: 0,
Msg: "ok",
Data: nil,
},
wantErr: false,
},
{
name: "post error",
args: args{
result: &StdResult{},
url: requestAddr + "/post_err",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
wantErr: true,
},
{
name: "post not found",
args: args{
result: &StdResult{},
url: requestAddr + "/notfound",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := Post(context.Background(), tt.args.result, tt.args.url, tt.args.body, WithHeaders(tt.args.headers), WithTimeout(tt.args.timeout))
if (err != nil) != tt.wantErr {
t.Errorf("Post() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.args.result.(*StdResult).Msg != tt.wantResult.Msg {
t.Errorf("gotResult = %v, wantResult = %v", tt.args.result, tt.wantResult)
}
})
}
}
func TestPut(t *testing.T) {
requestAddr := runGoHTTPServer()
type args struct {
result interface{}
url string
body interface{}
headers map[string]string
}
tests := []struct {
name string
args args
wantResult *StdResult
wantErr bool
}{
{
name: "put success",
args: args{
result: &StdResult{},
url: requestAddr + "/put",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "ok",
Data: nil,
},
wantErr: false,
},
{
name: "put error",
args: args{
result: &StdResult{},
url: requestAddr + "/put_err",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
wantErr: true,
},
{
name: "post not found",
args: args{
result: &StdResult{},
url: requestAddr + "/notfound",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := Put(context.Background(), tt.args.result, tt.args.url, tt.args.body, WithHeaders(tt.args.headers)); (err != nil) != tt.wantErr {
t.Errorf("Put() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.args.result.(*StdResult).Msg != tt.wantResult.Msg {
t.Errorf("gotResult = %v, wantResult = %v", tt.args.result, tt.wantResult)
}
})
}
}
func TestPatch(t *testing.T) {
requestAddr := runGoHTTPServer()
type args struct {
result interface{}
url string
body interface{}
headers map[string]string
}
tests := []struct {
name string
args args
wantResult *StdResult
wantErr bool
}{
{
name: "patch success",
args: args{
result: &StdResult{},
url: requestAddr + "/patch",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "ok",
Data: nil,
},
wantErr: false,
},
{
name: "patch error",
args: args{
result: &StdResult{},
url: requestAddr + "/patch_err",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
headers: map[string]string{
"Authorization": "Bearer token",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
wantErr: true,
},
{
name: "post not found",
args: args{
result: &StdResult{},
url: requestAddr + "/notfound",
body: &myBody{
Name: "foo",
Email: "bar@gmail.com",
},
},
wantResult: &StdResult{
Code: 0,
Msg: "",
Data: nil,
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := Patch(context.Background(), tt.args.result, tt.args.url, tt.args.body, WithHeaders(tt.args.headers)); (err != nil) != tt.wantErr {
t.Errorf("Put() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.args.result.(*StdResult).Msg != tt.wantResult.Msg {
t.Errorf("gotResult = %v, wantResult = %v", tt.args.result, tt.wantResult)
}
})
}
}
func TestRequest_Reset(t *testing.T) {
req := &Request{
method: http.MethodGet,
}
req.Reset()
assert.Equal(t, "", req.method)
}
func TestRequest_Do(t *testing.T) {
req := &Request{
method: http.MethodGet,
url: "http://",
}
_, err := req.Do(context.Background(), http.MethodOptions, "")
assert.Error(t, err)
_, err = req.Do(context.Background(), http.MethodGet, map[string]interface{}{"foo": "bar"})
assert.Error(t, err)
_, err = req.Do(context.Background(), http.MethodDelete, "foo=bar")
assert.Error(t, err)
_, err = req.Do(context.Background(), http.MethodPost, &myBody{
Name: "foo",
Email: "bar@gmail.com",
})
assert.Error(t, err)
_, err = req.Response()
assert.Error(t, err)
err = requestErr(err)
assert.Error(t, err)
err = jsonParseErr(err)
assert.Error(t, err)
}
func TestResponse_BodyString(t *testing.T) {
resp := &Response{
Body: nil,
err: nil,
}
_, err := resp.BodyString()
assert.Error(t, err)
resp.err = errors.New("error test")
_, err = resp.BodyString()
assert.Error(t, err)
err = resp.Error()
assert.Error(t, err)
}
func TestError(t *testing.T) {
req := New()
req.SetParam("foo", "bar")
req.SetParam("foo3", make(chan string))
req.SetParams(map[string]interface{}{"foo2": "bar2"})
req.SetBody("foo")
req.SetTimeout(time.Second * 10)
req.CustomRequest(func(req *http.Request, data *bytes.Buffer) {
fmt.Println("customRequest")
})
req.SetURL("http://127.0.0.1:0")
resp, err := req.pull(context.Background())
assert.Error(t, err)
_, err = resp.ReadBody()
assert.Error(t, err)
req.method = http.MethodPost
resp, err = req.push(context.Background())
assert.Error(t, err)
_, err = resp.ReadBody()
assert.Error(t, err)
err = resp.BindJSON(nil)
assert.Error(t, err)
err = notOKErr(resp)
assert.Error(t, err)
err = do(context.Background(), http.MethodPost, nil, "", nil, nil, nil, 0)
assert.Error(t, err)
err = do(context.Background(), http.MethodPost, &StdResult{}, "http://127.0.0.1:0", nil, KV{"foo": "bar"}, nil, 0)
assert.Error(t, err)
err = gDo(context.Background(), http.MethodGet, nil, "http://127.0.0.1:0", nil, nil, 0)
assert.Error(t, err)
} }
...@@ -17,10 +17,15 @@ type Request struct { ...@@ -17,10 +17,15 @@ type Request struct {
request *http.Request request *http.Request
response *http.Response response *http.Response
err error
} }
func New() *Request { func New() *Request {
return &Request{} return &Request{
request: &http.Request{},
headers: map[string]string{},
params: map[string]interface{}{},
}
} }
func (req *Request) SetURL(path string) *Request { func (req *Request) SetURL(path string) *Request {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论