From a11cc05a9dd43d7e0dfe7b6ec0992deb1350b8b0 Mon Sep 17 00:00:00 2001 From: renzhiyuan <465386466@qq.com> Date: Wed, 19 Feb 2025 15:17:34 +0800 Subject: [PATCH] first push --- README.md | 25 ++++++++++ go.mod | 3 ++ pool.go | 43 +++++++++++++++++ pool_test.go | 11 +++++ request.go | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 212 insertions(+) create mode 100644 README.md create mode 100644 go.mod create mode 100644 pool.go create mode 100644 pool_test.go create mode 100644 request.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..f895ffe --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +## 安装 + +```bash +$ go get -u gitea.cdlsxd.cn/rzy_tools/request/tags +``` + + +## 正常使用 +```go + req := request.Request{ + Method: "POST", + Url: reqUrl, + Json: RequestBody, + Headers: header, + } + resp, _ := req.Send() +``` + +## 同时大量请求或者在协程中使用建议使用 + +```go + r := RequestPools.Get() + defer RequestPools.ClearAndPut(r) + ... +``` \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ed49f88 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module gitea.cdlsxd.cn/self-tools/l-request + +go 1.23.6 diff --git a/pool.go b/pool.go new file mode 100644 index 0000000..56d092b --- /dev/null +++ b/pool.go @@ -0,0 +1,43 @@ +package l_request + +import ( + "sync" +) + +type RequestPool struct { + pool sync.Pool +} + +var RequestPools = &RequestPool{ + pool: sync.Pool{ + New: func() interface{} { + return new(Request) + }, + }, +} + +func (re *RequestPool) Get() *Request { + return re.pool.Get().(*Request) +} + +func (re *RequestPool) Put(r *Request) { + re.pool.Put(r) +} + +func (re *RequestPool) Reset(r *Request) { + r.Method = "" + r.Url = "" + r.Params = nil + r.Headers = nil + r.Cookies = nil + r.Data = nil + r.Json = nil + r.Files = nil + r.Raw = "" + r.JsonByte = nil +} + +func (re *RequestPool) ClearAndPut(r *Request) { + re.Reset(r) + re.Put(r) +} diff --git a/pool_test.go b/pool_test.go new file mode 100644 index 0000000..596177f --- /dev/null +++ b/pool_test.go @@ -0,0 +1,11 @@ +package l_request + +import "testing" + +func TestPool(t *testing.T) { + r := RequestPools.Get() + r.Url = "http://www.baidu.com" + RequestPools.ClearAndPut(r) + a := RequestPools.Get() + t.Log(a.Url) +} diff --git a/request.go b/request.go new file mode 100644 index 0000000..65f5618 --- /dev/null +++ b/request.go @@ -0,0 +1,130 @@ +package l_request + +import ( + "encoding/json" + "io" + "net/http" + "net/url" + "strings" + "time" +) + +// 请求结构体 +type Request struct { + Method string `json:"method"` // 请求方法 + Url string `json:"url"` // 请求url + Params map[string]string `json:"params"` // Query参数 + Headers map[string]string `json:"headers"` // 请求头 + Cookies map[string]string `json:"cookies"` // todo 处理 Cookies + Data map[string]string `json:"data"` // 表单格式请求数据 + Json map[string]interface{} `json:"json"` // JSON格式请求数据 todo 多层 嵌套 + Files map[string]string `json:"files"` // todo 处理 Files + Raw string `json:"raw"` // 原始请求数据 + JsonByte []byte `json:"json_raw"` // JSON格式请求数据 todo 多层 嵌套 +} + +// 响应结构体 +type Response struct { + StatusCode int `json:"status_code"` // 状态码 + Reason string `json:"reason"` // 状态码说明 + Elapsed float64 `json:"elapsed"` // 请求耗时(秒) + Content []byte `json:"content"` // 响应二进制内容 + Text string `json:"text"` // 响应文本 + Headers map[string]string `json:"headers"` // 响应头 + Cookies map[string]string `json:"cookies"` // todo 添加响应Cookies + Request *Request `json:"request"` // 原始请求 +} + +// 处理请求方法 +func (r *Request) getMethod() string { + return strings.ToUpper(r.Method) // 必须转为全部大写 +} + +// 组装URL +func (r *Request) getUrl() string { + if r.Params != nil { + urlValues := url.Values{} + Url, _ := url.Parse(r.Url) // todo 处理err + for key, value := range r.Params { + urlValues.Set(key, value) + } + Url.RawQuery = urlValues.Encode() + return Url.String() + } + return r.Url +} + +// 组装请求数据 +func (r *Request) getData() io.Reader { + var reqBody string + if r.Headers == nil { + r.Headers = make(map[string]string, 1) + } + if r.Raw != "" { + reqBody = r.Raw + } else if r.Data != nil { + urlValues := url.Values{} + for key, value := range r.Data { + urlValues.Add(key, value) + } + reqBody = urlValues.Encode() + r.Headers["Content-Type"] = "application/x-www-form-urlencoded" + } else if r.Json != nil { + bytesData, _ := json.Marshal(r.Json) + reqBody = string(bytesData) + r.Headers["Content-Type"] = "application/json" + } else if r.JsonByte != nil { + reqBody = string(r.JsonByte) + r.Headers["Content-Type"] = "application/json" + } + return strings.NewReader(reqBody) +} + +// 添加请求头-需要在getData后使用 +func (r *Request) addHeaders(req *http.Request) { + if r.Headers != nil { + for key, value := range r.Headers { + req.Header.Add(key, value) + } + } +} + +// 准备请求 +func (r *Request) prepare() *http.Request { + Method := r.getMethod() + Url := r.getUrl() + Data := r.getData() + req, _ := http.NewRequest(Method, Url, Data) + r.addHeaders(req) + return req +} + +// 组装响应对象 +func (r *Request) packResponse(res *http.Response, elapsed float64) Response { + var resp Response + resBody, _ := io.ReadAll(res.Body) + resp.Content = resBody + resp.Text = string(resBody) + resp.StatusCode = res.StatusCode + resp.Reason = strings.Split(res.Status, " ")[1] + resp.Elapsed = elapsed + resp.Headers = map[string]string{} + for key, value := range res.Header { + resp.Headers[key] = strings.Join(value, ";") + } + return resp +} + +// 发送请求 +func (r *Request) Send() (Response, error) { + req := r.prepare() + client := &http.Client{} + start := time.Now() + res, err := client.Do(req) + if err != nil { + return Response{}, err + } + defer res.Body.Close() + elapsed := time.Since(start).Seconds() + return r.packResponse(res, elapsed), nil +}