From 0931539e1c9502144c62245894ee0e85e2dd2844 Mon Sep 17 00:00:00 2001 From: Yun Date: Sun, 28 Dec 2025 15:14:05 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=B0=81=E8=A3=85=E7=9A=84?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- consts.go | 17 +++++++ curlx.go | 124 +++++++++++++++++--------------------------------- curlx_test.go | 22 ++++----- options.go | 15 +++++- resopnse.go | 114 +++++++++++++++++++++++++++------------------- types.go | 12 ----- 6 files changed, 151 insertions(+), 153 deletions(-) create mode 100644 consts.go delete mode 100644 types.go diff --git a/consts.go b/consts.go new file mode 100644 index 0000000..aec41cb --- /dev/null +++ b/consts.go @@ -0,0 +1,17 @@ +package curlx + +import "errors" + +type UserAgent string + +const ( + UserAgentChrome UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " + UserAgentFirefox UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 " + UserAgentIE UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; " + UserAgentEdge UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " + UserAgentWechat UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 " +) + +var ( + ErrStatusNotOK error = errors.New("Status not ok") +) diff --git a/curlx.go b/curlx.go index 2bd7c19..58319eb 100644 --- a/curlx.go +++ b/curlx.go @@ -2,10 +2,8 @@ package curlx import ( "bufio" - "compress/gzip" "context" "fmt" - "io" "net" "net/http" "net/url" @@ -122,43 +120,29 @@ func (c *Curlx) WithAddress(ctx context.Context, addr string) { /** * 简单请求 */ -func (c *Curlx) Send(ctx context.Context, p ...Param) (res []byte, httpcode int, err error) { - _, response, err := c.SendExec(ctx, p...) - if err != nil { - return nil, -1, err +func (c *Curlx) Send(ctx context.Context, p ...Param) (res []byte, err error) { + resp := c.exec(ctx, p...) + if resp.Err != nil { + return nil, resp.Err + } + defer resp.Close() // 处理完关闭 + + status := resp.GetStatusCode() + if status != 200 { + return nil, ErrStatusNotOK } - defer response.Body.Close() // 处理完关闭 - - // stdout := os.Stdout // 将结果定位到标准输出,也可以直接打印出来,或定位到其他地方进行相应处理 - // _, err = io.Copy(stdout, response.Body) // 将第二个参数拷贝到第一个参数,直到第二参数到达EOF或发生错误,返回拷贝的值 - status := response.StatusCode // 获取状态码,正常是200 - - var body []byte - - if response.Header.Get("Content-Encoding") == "gzip" { - reader, err := gzip.NewReader(response.Body) - if err != nil { - return nil, response.StatusCode, err - } - body, err = io.ReadAll(reader) - if err != nil { - return nil, response.StatusCode, err - } - defer reader.Close() - } else { - body, err = io.ReadAll(response.Body) - if err != nil { - return nil, response.StatusCode, err - } + body, err := resp.GetBody() + if err != nil { + return nil, err } c.opts.Logger.Infof(ctx, "curlx.Send body:%s", string(body)) - return body, status, nil + return body, nil } // PostJson 发送JSON数据 -func (l *Curlx) PostJson(ctx context.Context, url string, jsonStr string) ([]byte, int, error) { +func (l *Curlx) PostJson(ctx context.Context, url string, jsonStr string) ([]byte, error) { return l.Send(ctx, SetParamsUrl(url), SetParamsBody([]byte(jsonStr)), @@ -168,55 +152,24 @@ func (l *Curlx) PostJson(ctx context.Context, url string, jsonStr string) ([]byt } // Get 简单GET请求 -func (l *Curlx) Get(ctx context.Context, url string) ([]byte, int, error) { +func (l *Curlx) Get(ctx context.Context, url string) ([]byte, error) { return l.Send(ctx, SetParamsUrl(url), SetParamsMethod(MethodGet), ) } -func (c *Curlx) SendWithResponee(ctx context.Context, ps ...Param) Response { - r := Response{} - req, resp, err := c.SendExec(ctx, ps...) - r.req = req - r.resp = resp - - if err != nil { - r.err = err - return r - } - var body []byte - - if resp.Header.Get("Content-Encoding") == "gzip" { - reader, err := gzip.NewReader(resp.Body) - if err != nil { - r.err = err - return r - } - body, err = io.ReadAll(reader) - if err != nil { - r.err = err - return r - } - defer reader.Close() - } else { - body, err = io.ReadAll(resp.Body) - if err != nil { - r.err = err - return r - } - } - - r.body = body - c.opts.Logger.Infof(ctx, "curlx.Send body:%s", string(body)) - return r +func (c *Curlx) SendWithResponse(ctx context.Context, ps ...Param) Response { + return c.exec(ctx, ps...) } /** * 执行发送 * 注意:外部使用需要加这一句 defer response.Body.Close() */ -func (c *Curlx) SendExec(ctx context.Context, ps ...Param) (req *http.Request, resp *http.Response, err error) { +func (c *Curlx) exec(ctx context.Context, ps ...Param) Response { + resp := Response{} + client := &http.Client{ Timeout: c.opts.TimeOut, // 整个请求的超时时间 设置该条连接的超时 Transport: c.transport, // @@ -228,23 +181,27 @@ func (c *Curlx) SendExec(ctx context.Context, ps ...Param) (req *http.Request, r } c.opts.Logger.Infof(ctx, "curlx.sendExec params:%+v", p) - err = p.parseMethod() + err := p.parseMethod() if err != nil { - return nil, nil, err + c.opts.Logger.Errorf(ctx, "curlx.sendExec parseMethod err:%v", err) + resp.Err = err + return resp } // 判断和处理url err = p.parseUrl() if err != nil { c.opts.Logger.Errorf(ctx, "curlx.sendExec parseUrl err:%v", err) - return nil, nil, err + resp.Err = err + return resp } // 处理参数 reqParams, err := p.parseParams() if err != nil { c.opts.Logger.Errorf(ctx, "curlx.sendExec parseParams err:%v", err) - return nil, nil, err + resp.Err = err + return resp } // 初始化句柄 @@ -255,9 +212,13 @@ func (c *Curlx) SendExec(ctx context.Context, ps ...Param) (req *http.Request, r ) if err != nil { c.opts.Logger.Errorf(ctx, "curlx.sendExec NewRequest err:%v", err) - return nil, nil, err + resp.Err = err + return resp } + c.opts.Logger.Infof(ctx, "curlx.sendExec request:%+v", request) + resp.Request = request + // 这里指定要访问的HOST,到时候服务器获取主机是获取到这个 // request.Host = "api.hk.blueoceantech.co" @@ -274,10 +235,12 @@ func (c *Curlx) SendExec(ctx context.Context, ps ...Param) (req *http.Request, r response, err := client.Do(request) if err != nil { c.opts.Logger.Errorf(ctx, "curlx.sendExec client.Do err:%v", err) - return nil, nil, err + resp.Err = err + return resp } - // response.StatusCode - return request, response, nil + resp.Response = response + + return resp } /** @@ -293,13 +256,12 @@ func (c *Curlx) SendStream(ctx context.Context, ps ...Param) (<-chan string, err ctx, cancel := context.WithTimeout(context.Background(), c.opts.TimeOut) defer cancel() - _, response, err := c.SendExec(ctx, ps...) - if err != nil { + response := c.exec(ctx, ps...) + if response.Err != nil { return } - defer response.Body.Close() // 处理完关闭 - - scanner := bufio.NewScanner(response.Body) + defer response.Close() // 处理完关闭 + scanner := bufio.NewScanner(response.Response.Body) for scanner.Scan() { text := scanner.Text() if text == "" { diff --git a/curlx_test.go b/curlx_test.go index f96e6c9..1bcf729 100644 --- a/curlx_test.go +++ b/curlx_test.go @@ -11,11 +11,11 @@ import ( ) func TestGet(t *testing.T) { - resp, code, err := NewCurlx().Send(context.Background(), + resp, err := NewCurlx().Send(context.Background(), SetParamsUrl("https://www.baidu.com"), SetParamsMethod(MethodGet), ) - t.Log(resp, code, err) + t.Log(string(resp), err) } @@ -41,22 +41,22 @@ func TestForm(t *testing.T) { by, _ := json.Marshal(s) p := ClientParams{ - Url: "http://tech-dev.sealmoo.com/api/material/upload", - Method: "POST", - Body: by, - Headers: http.Header{ - "Content-Type": []string{"application/json"}, + Url: "http://tech-dev.sealmoo.com/api/material/upload", + Method: "POST", + Body: by, + Headers: http.Header{ + "Content-Type": []string{"application/json"}, "Authorization": []string{"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZW5hbnRfaWQiOjAsImNsaWVudF9pZCI6MCwidXNlcl9pZCI6MSwiZXhwIjoxNzAxMzk3NzkxfQ.9_uJ6y8I4JZTwgSenwHC_01nddLuI4zmgpyPhn5M6j8"}, }, ContentType: ContentTypeForm, } - resp, code, err := NewCurlx().Send(context.Background(), SetParamsAll(p)) - fmt.Println(resp, code, err) + resp, err := NewCurlx().Send(context.Background(), SetParamsAll(p)) + fmt.Println(resp, err) } func TestProxy(t *testing.T) { c := NewCurlx() c.WithProxySocks5("127.0.0.1:1080") - res, code, err := c.Send(context.Background(), SetParamsUrl("https://www.google.com"), SetParamsMethod(MethodGet)) - t.Log(string(res), code, err) + res, err := c.Send(context.Background(), SetParamsUrl("https://www.google.com"), SetParamsMethod(MethodGet)) + t.Log(string(res), err) } diff --git a/options.go b/options.go index e6f9c64..2132495 100644 --- a/options.go +++ b/options.go @@ -10,12 +10,14 @@ type clientOptions struct { TimeOut time.Duration InsecureSkipVerify bool Logger OptionLogger + LoggerLength int // 日志输出长度 } func defaultOptions() clientOptions { return clientOptions{ - TimeOut: time.Second * 120, // 默认超时120 - Logger: defaultLogger{}, + TimeOut: time.Second * 120, // 默认超时120 + Logger: defaultLogger{}, + LoggerLength: 100, } } @@ -48,6 +50,15 @@ func SetOptionLog(log OptionLogger) Option { } } +/** + * 设置日志输出长度 + */ +func WithLoggerLength(length int) Option { + return func(options *clientOptions) { + options.LoggerLength = length + } +} + type OptionLogger interface { Infof(ctx context.Context, format string, args ...interface{}) Errorf(ctx context.Context, format string, args ...interface{}) diff --git a/resopnse.go b/resopnse.go index 90b6f24..7edc69e 100644 --- a/resopnse.go +++ b/resopnse.go @@ -1,6 +1,8 @@ package curlx import ( + "compress/gzip" + "io" "net" "net/http" "strings" @@ -10,70 +12,77 @@ import ( // Response response object type Response struct { - resp *http.Response - req *http.Request - body []byte - err error + Response *http.Response + Request *http.Request + Body []byte + Err error } -// ResponseBody response body -type ResponseBody []byte - -// String fmt outout -func (r ResponseBody) String() string { - return string(r) -} - -// Read get slice of response body -func (r ResponseBody) Read(length int) []byte { - if length > len(r) { - length = len(r) +func (l *Response) Close() error { + if l.Response.Body != nil { + return l.Response.Body.Close() } - - return r[:length] -} - -// GetContents format response body as string -func (r ResponseBody) GetContents() string { - return string(r) + return nil } // GetRequest get request object func (r *Response) GetRequest() *http.Request { - return r.req + return r.Request +} + +func (r *Response) GetResponse() *http.Response { + return r.Response } // GetBody parse response body -func (r *Response) GetBody() (ResponseBody, error) { - return ResponseBody(r.body), r.err +func (r *Response) GetBody() ([]byte, error) { + if r.Err != nil { + return nil, r.Err + } + if r.Body != nil { + return r.Body, nil + } + if r.Response == nil { + return nil, nil + } + body := []byte{} + var err error + if r.Response.Header.Get("Content-Encoding") == "gzip" { + reader, err := gzip.NewReader(r.Response.Body) + if err != nil { + return nil, err + } + defer reader.Close() + body, err = io.ReadAll(reader) + if err != nil { + return nil, err + } + } else { + body, err = io.ReadAll(r.Response.Body) + if err != nil { + return nil, err + } + } + // close body + r.Response.Body.Close() + + r.Body = body + return body, err } -// GetParsedBody parse response body with gjson -func (r *Response) GetParsedBody() (*gjson.Result, error) { - pb := gjson.ParseBytes(r.body) - - return &pb, nil -} - -// GetStatusCode get response status code -func (r *Response) GetStatusCode() int { - return r.resp.StatusCode -} - -// GetReasonPhrase get response reason phrase -func (r *Response) GetReasonPhrase() string { - status := r.resp.Status - arr := strings.Split(status, " ") - - return arr[1] +func (r Response) GetStatusCode() int { + if r.Response == nil { + return 0 + } + return r.Response.StatusCode } // IsTimeout get if request is timeout func (r *Response) IsTimeout() bool { - if r.err == nil { + if r.Err == nil { return false } - netErr, ok := r.err.(net.Error) + netErr, ok := r.Err.(net.Error) if !ok { return false } @@ -84,9 +93,20 @@ func (r *Response) IsTimeout() bool { return false } +// GetParsedBody parse response body with gjson +func (r *Response) GetParsedBody() (*gjson.Result, error) { + body, err := r.GetBody() + if err != nil { + return nil, err + } + pb := gjson.ParseBytes(body) + + return &pb, nil +} + // GetHeaders get response headers func (r *Response) GetHeaders() map[string][]string { - return r.resp.Header + return r.Response.Header } // GetHeader get response header diff --git a/types.go b/types.go deleted file mode 100644 index fe293c0..0000000 --- a/types.go +++ /dev/null @@ -1,12 +0,0 @@ -package curlx - - -type UserAgent string - -const( - UserAgentChrome UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " - UserAgentFirefox UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 " - UserAgentIE UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; " - UserAgentEdge UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " - UserAgentWechat UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 " -) \ No newline at end of file