From 4d2aabaff5aea410eab51c069938a1d5e935adad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=85=89=E6=98=A5?= Date: Fri, 29 Apr 2022 11:57:33 +0800 Subject: [PATCH] init --- .gitignore | 8 + LICENSE | 21 ++ README.md | 25 +++ go.mod | 5 + go.sum | 2 + header.go | 30 +++ http.go | 201 ++++++++++++++++++ ip.go | 46 ++++ params.go | 40 ++++ user_agent.go | 73 +++++++ vendor/github.com/nilorg/sdk/LICENSE | 21 ++ .../github.com/nilorg/sdk/convert/convert.go | 112 ++++++++++ vendor/modules.txt | 3 + 13 files changed, 587 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 header.go create mode 100644 http.go create mode 100644 ip.go create mode 100644 params.go create mode 100644 user_agent.go create mode 100644 vendor/github.com/nilorg/sdk/LICENSE create mode 100644 vendor/github.com/nilorg/sdk/convert/convert.go create mode 100644 vendor/modules.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..34509e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.env +.git +.svn +.idea +.vscode +*.log +gitmod.sh +*_test.go \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a0d0e5b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 茂名聚合科技有限公司 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2f62206 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +

+Golang Request +

+ +📦 Golang 请求组件 + +[comment]: <> (go) +[![godoc](https://pkg.go.dev/badge/github.com/dtapps/gorequest?status.svg)](https://pkg.go.dev/github.com/dtapps/gorequest) +[![goproxy.cn](https://goproxy.cn/stats/github.com/dtapps/gorequest/badges/download-count.svg)](https://goproxy.cn/stats/github.com/dtapps/gorequest) +[![goreportcard.com](https://goreportcard.com/badge/github.com/dtapps/gorequest)](https://goreportcard.com/report/github.com/dtapps/gorequest) +[![deps.dev](https://img.shields.io/badge/deps-go-red.svg)](https://deps.dev/go/github.com%2Fdtapps%2Fgorequest) + +#### 安装使用 + +```go +go get -v -u github.com/dtapps/gorequest +``` + +#### 导入 + +```go +import ( + "github.com/dtapps/gorequest" +) +``` \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..cf5f11a --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/dtapps/gorequest + +go 1.18 + +require github.com/nilorg/sdk v0.0.0-20210429091026-95b6cdc95c84 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7a10f97 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/nilorg/sdk v0.0.0-20210429091026-95b6cdc95c84 h1:Nxk1uViXfb9MHgtHBlQFWzlQCsJbDQuotfTsAFcFP3o= +github.com/nilorg/sdk v0.0.0-20210429091026-95b6cdc95c84/go.mod h1:X1swpPdqguAZaBDoEPyEWHSsJii0YQ1o+3piMv6W3JU= diff --git a/header.go b/header.go new file mode 100644 index 0000000..ddde4c1 --- /dev/null +++ b/header.go @@ -0,0 +1,30 @@ +package gorequest + +import ( + "net/url" +) + +type Headers map[string]string + +func NewHeaders() Headers { + P := make(Headers) + return P +} + +func (p Headers) Set(key, value string) { + p[key] = value +} + +func (p Headers) SetHeaders(headers Headers) { + for key, value := range headers { + p[key] = value + } +} + +func (p Headers) GetQuery() string { + u := url.Values{} + for k, v := range p { + u.Set(k, v) + } + return u.Encode() +} diff --git a/http.go b/http.go new file mode 100644 index 0000000..ba83779 --- /dev/null +++ b/http.go @@ -0,0 +1,201 @@ +package gorequest + +import ( + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" +) + +// Response 返回内容 +type Response struct { + RequestUrl string //【请求】链接 + RequestParams url.Values //【请求】参数 + RequestMethod string //【请求】方式 + RequestHeader http.Header //【请求】头部 + ResponseHeader http.Header //【返回】头部 + ResponseStatus string //【返回】状态 + ResponseStatusCode int //【返回】状态码 + ResponseBody []byte //【返回】内容 + ResponseContentLength int64 //【返回】大小 +} + +type app struct { + httpUrl string // 请求地址 + httpMethod string // 请求方法 + httpHeader Headers // 请求头 + httpParams Params // 请求参数 + httpParamsMode string // 请求参数方式 + responseContent Response // 返回内容 +} + +var ( + httpParamsModeJson = "json" + httpParamsModeForm = "form" +) + +// NewHttp 实例化 +func NewHttp() *app { + return &app{ + httpHeader: NewHeaders(), + httpParams: NewParams(), + } +} + +// SetUrl 设置请求地址 +func (app *app) SetUrl(url string) { + app.httpUrl = url +} + +// SetMethod 设置请求方式地址 +func (app *app) SetMethod(method string) { + app.httpMethod = method +} + +// SetHeader 设置请求头 +func (app *app) SetHeader(key, value string) { + if key == "" { + panic("url is empty") + } + app.httpHeader.Set(key, value) +} + +// SetHeaders 批量设置请求头 +func (app *app) SetHeaders(headers Headers) { + for key, value := range headers { + app.httpHeader.Set(key, value) + } +} + +// SetAuthToken 设置身份验证令牌 +func (app *app) SetAuthToken(token string) { + app.httpHeader.Set("Authorization", fmt.Sprintf("Bearer %s", token)) +} + +// SetUserAgent 设置用户代理,空字符串就随机设置 +func (app *app) SetUserAgent(ua string) { + if ua == "" { + ua = GetRandomUserAgent() + } + app.httpHeader.Set("User-Agent", ua) +} + +// SetContentTypeJson 设置JSON格式 +func (app *app) SetContentTypeJson() { + app.httpParamsMode = httpParamsModeJson + app.httpHeader.Set("Content-Type", "application/json") +} + +// SetContentTypeForm 设置FORM格式 +func (app *app) SetContentTypeForm() { + app.httpParamsMode = httpParamsModeForm + app.httpHeader.Set("Content-Type", "application/x-www-form-urlencoded") +} + +// SetParam 设置请求参数 +func (app *app) SetParam(key string, value interface{}) { + app.httpParams.Set(key, value) +} + +// SetParams 批量设置请求参数 +func (app *app) SetParams(params Params) { + for key, value := range params { + app.httpParams.Set(key, value) + } +} + +// Get 发起GET请求 +func (app *app) Get() (httpResponse Response, err error) { + // 设置请求方法 + app.httpMethod = http.MethodGet + return request(app) +} + +// Post 发起POST请求 +func (app *app) Post() (httpResponse Response, err error) { + // 设置请求方法 + app.httpMethod = http.MethodPost + return request(app) +} + +// Request 发起请求 +func (app *app) Request() (httpResponse Response, err error) { + return request(app) +} + +// 请求 +func request(app *app) (httpResponse Response, err error) { + + // 创建 http 客户端 + client := &http.Client{} + + // 赋值 + httpResponse.RequestUrl = app.httpUrl + httpResponse.RequestMethod = app.httpMethod + + // 携带 form 参数 + form := url.Values{} + if app.httpMethod == http.MethodPost && app.httpParamsMode == httpParamsModeForm { + if len(app.httpParams) > 0 { + for k, v := range app.httpParams { + form.Add(k, GetParamsString(v)) + } + // 赋值 + httpResponse.RequestParams = form + } + } + + // 创建请求 + req, err := http.NewRequest(app.httpMethod, app.httpUrl, strings.NewReader(form.Encode())) + if err != nil { + return httpResponse, errors.New(fmt.Sprintf("创建请求出错 %s", err)) + } + + // GET 请求携带查询参数 + if app.httpMethod == http.MethodGet { + if len(app.httpParams) > 0 { + q := req.URL.Query() + for k, v := range app.httpParams { + q.Add(k, GetParamsString(v)) + } + req.URL.RawQuery = q.Encode() + // 赋值 + httpResponse.RequestParams = q + } + } + + // 设置请求头 + if len(app.httpHeader) > 0 { + for key, value := range app.httpHeader { + req.Header.Set(key, value) + } + // 赋值 + httpResponse.RequestHeader = req.Header + } + + // 发送请求 + resp, err := client.Do(req) + if err != nil { + return httpResponse, errors.New(fmt.Sprintf("请求出错 %s", err)) + } + + // 最后关闭连接 + defer resp.Body.Close() + + // 读取内容 + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return httpResponse, errors.New(fmt.Sprintf("解析内容出错 %s", err)) + } + + // 赋值 + httpResponse.ResponseStatus = resp.Status + httpResponse.ResponseStatusCode = resp.StatusCode + httpResponse.ResponseHeader = resp.Header + httpResponse.ResponseBody = body + httpResponse.ResponseContentLength = resp.ContentLength + + return httpResponse, err +} diff --git a/ip.go b/ip.go new file mode 100644 index 0000000..d7811a9 --- /dev/null +++ b/ip.go @@ -0,0 +1,46 @@ +package gorequest + +import ( + "net" + "net/http" + "strings" +) + +// ClientIp 尽最大努力实现获取客户端 IP 的算法。 +// 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。 +func ClientIp(r *http.Request) string { + + // 转发IP + xForwardedFor := r.Header.Get("X-Forwarded-For") + ip := strings.TrimSpace(strings.Split(xForwardedFor, ",")[0]) + if ip != "" { + return ip + } + + // 真实Ip + ip = strings.TrimSpace(r.Header.Get("X-Real-Ip")) + if ip != "" { + return ip + } + + // HTTP客户端IP + httpClientIp := r.Header.Get("HTTP_CLIENT_IP") + ip = strings.TrimSpace(strings.Split(httpClientIp, ",")[0]) + if ip != "" { + return ip + } + + // HTTP转发IP + HttpXForwardedFor := r.Header.Get("HTTP_X_FORWARDED_FOR") + ip = strings.TrimSpace(strings.Split(HttpXForwardedFor, ",")[0]) + if ip != "" { + return ip + } + + // 系统 + if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil { + return ip + } + + return "" +} diff --git a/params.go b/params.go new file mode 100644 index 0000000..85c2752 --- /dev/null +++ b/params.go @@ -0,0 +1,40 @@ +package gorequest + +import ( + "encoding/json" + "github.com/nilorg/sdk/convert" + "log" +) + +type Params map[string]interface{} + +func NewParams() Params { + P := make(Params) + return P +} + +func (p Params) Set(key string, value interface{}) { + p[key] = value +} + +func (p Params) SetParams(params Params) { + for key, value := range params { + p[key] = value + } +} + +func GetParamsString(src interface{}) string { + switch src.(type) { + case string: + return src.(string) + case int, int8, int32, int64: + case uint8, uint16, uint32, uint64: + case float32, float64: + return convert.ToString(src) + } + data, err := json.Marshal(src) + if err != nil { + log.Fatal(err) + } + return string(data) +} diff --git a/user_agent.go b/user_agent.go new file mode 100644 index 0000000..3ecd1bc --- /dev/null +++ b/user_agent.go @@ -0,0 +1,73 @@ +package gorequest + +import ( + "fmt" + "math/rand" + "runtime" + "time" +) + +// GetRandomUserAgent 获取随机UA +func GetRandomUserAgent() string { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + return userAgentList[r.Intn(len(userAgentList))] +} + +var userAgentList = []string{ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36", // Chrome 2022-02-14 + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0", // Firefox 2022-02-14 + "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko", // IE 2022-02-14 + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36 HeyTapBrowser/40.7.35.1", // Chrome 2022-02-14 + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36 OnePlusBrowser/30.5.0.8", // Chrome 2022-02-14 + "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a1) Gecko/20060814 Firefox/51.0", // Firefox 2022-02-14 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15", // Safari 2022-02-14 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15", // Safari 2022-04-18 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36 Edg/98.0.1108.51", // Edge 2022-02-14 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36 Edg/100.0.1185.44", // Chrome 2022-04-18 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36", // Chrome 2022-02-14 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36", // Chrome 2022-04-18 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:97.0) Gecko/20100101 Firefox/97.0", // Firefox 2022-02-14 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:99.0) Gecko/20100101 Firefox/99.0", // Firefox 2022-04-18 +} + +// GetRandomUserAgentSystem 获取系统随机UA +func GetRandomUserAgentSystem() string { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + switch runtime.GOOS { + case "linux": + return userAgentListLinux[r.Intn(len(userAgentListLinux))] + case "windows": + return userAgentListWindows[r.Intn(len(userAgentListWindows))] + default: + return userAgentListMac[r.Intn(len(userAgentListMac))] + } +} + +var userAgentListWindows = []string{ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36", // Chrome 2022-02-14 + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0", // Firefox 2022-02-14 + "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko", // IE 2022-02-14 +} + +var userAgentListLinux = []string{ + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36 HeyTapBrowser/40.7.35.1", // Chrome 2022-02-14 + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36 OnePlusBrowser/30.5.0.8", // Chrome 2022-02-14 + "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a1) Gecko/20060814 Firefox/51.0", // Firefox 2022-02-14 +} + +var userAgentListMac = []string{ + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15", // Safari 2022-02-14 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15", // Safari 2022-04-18 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36 Edg/98.0.1108.51", // Edge 2022-02-14 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36 Edg/100.0.1185.44", // Chrome 2022-04-18 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36", // Chrome 2022-02-14 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36", // Chrome 2022-04-18 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:97.0) Gecko/20100101 Firefox/97.0", // Firefox 2022-02-14 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:99.0) Gecko/20100101 Firefox/99.0", // Firefox 2022-04-18 +} + +func DtaUa() string { + str := runtime.Version() + content := str[2 : len(str)-0] + return fmt.Sprintf("DTA-Go/%v", content) +} diff --git a/vendor/github.com/nilorg/sdk/LICENSE b/vendor/github.com/nilorg/sdk/LICENSE new file mode 100644 index 0000000..a122b0f --- /dev/null +++ b/vendor/github.com/nilorg/sdk/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Nil Org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/nilorg/sdk/convert/convert.go b/vendor/github.com/nilorg/sdk/convert/convert.go new file mode 100644 index 0000000..2ce0fa2 --- /dev/null +++ b/vendor/github.com/nilorg/sdk/convert/convert.go @@ -0,0 +1,112 @@ +package convert + +import ( + "bytes" + "encoding/binary" + "fmt" + "strconv" +) + +// ToString 转换成string +func ToString(value interface{}) string { + if value == nil { + return "" + } + return fmt.Sprint(value) +} + +// ToBool 转换成Bool +func ToBool(i interface{}) bool { + switch b := i.(type) { + case bool: + return b + case nil: + return false + case int: + if i.(int) != 0 { + return true + } + return false + case string: + v, err := strconv.ParseBool(ToString(i)) + if err != nil { + return false + } + return v + default: + return false + } +} + +// ToInt 转换成int +func ToInt(value interface{}) int { + return int(ToInt64(value)) +} + +// ToInt32 转换成int32 +func ToInt32(value interface{}) int32 { + return int32(ToInt64(value)) +} + +// ToInt64 转换成int64 +func ToInt64(value interface{}) int64 { + num, err := strconv.ParseInt(ToString(value), 10, 64) + if err != nil { + return 0 + } + return num +} + +// ToUint 转换成uint +func ToUint(value interface{}) uint { + return uint(ToUint64(value)) +} + +// ToUint32 转换成uint32 +func ToUint32(value interface{}) uint32 { + return uint32(ToUint64(value)) +} + +// ToUint64 转换成uint64 +func ToUint64(value interface{}) uint64 { + num, err := strconv.ParseUint(ToString(value), 10, 64) + if err != nil { + return 0 + } + return num +} + +// ToFloat32 转换成float32 +func ToFloat32(value interface{}) float32 { + return float32(ToFloat64(value)) +} + +// ToFloat64 转换成float64 +func ToFloat64(value interface{}) float64 { + num, err := strconv.ParseFloat(ToString(value), 64) + if err != nil { + return 0 + } + return num +} + +// BytesToInt32 字节转Int32 +func BytesToInt32(data []byte) int32 { + var num int32 + buffer := bytes.NewBuffer(data) + binary.Read(buffer, binary.BigEndian, &num) + return num +} + +// BytesToInt 字节转Int +func BytesToInt(data []byte) int { + return int(BytesToInt32(data)) +} + +// BytesToInt64 字节转Int64 +func BytesToInt64(data []byte) int64 { + var num int64 + buffer := bytes.NewBuffer(data) + binary.Read(buffer, binary.BigEndian, &num) + return num +} diff --git a/vendor/modules.txt b/vendor/modules.txt new file mode 100644 index 0000000..15cb268 --- /dev/null +++ b/vendor/modules.txt @@ -0,0 +1,3 @@ +# github.com/nilorg/sdk v0.0.0-20210429091026-95b6cdc95c84 +## explicit; go 1.12 +github.com/nilorg/sdk/convert