diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b2420d9..eb7e7102 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - files:更新 - ip:更新 - storage:增加存储功能 +- request:合并http ## v1.0.39 / 2021-12-27 diff --git a/utils/gohttp/gohttp.go b/utils/gohttp/gohttp.go deleted file mode 100644 index 50daf69b..00000000 --- a/utils/gohttp/gohttp.go +++ /dev/null @@ -1,281 +0,0 @@ -package gohttp - -import ( - "bytes" - "crypto/tls" - "encoding/json" - "errors" - "fmt" - "go.dtapp.net/library/utils/goheader" - "go.dtapp.net/library/utils/gorequest" - "io" - "io/ioutil" - "net/http" - "net/url" - "strconv" - "strings" -) - -type Response struct { - Status string - StatusCode int - Header http.Header - Body []byte - ContentLength int64 -} - -func Get(url string, params map[string]interface{}) (httpResponse Response, err error) { - // 创建 http 客户端 - client := &http.Client{} - // 创建请求 - req, _ := http.NewRequest(http.MethodGet, url, nil) - if len(params) > 0 { - // GET 请求携带查询参数 - q := req.URL.Query() - for k, v := range params { - q.Add(k, getString(v)) - } - req.URL.RawQuery = q.Encode() - } - // 设置请求头 - req.Header.Set("User-Agent", gorequest.GetRandomUserAgent()) - // 发送请求 - resp, err := client.Do(req) - if err != nil { - // 格式化返回错误 - return httpResponse, errors.New(fmt.Sprintf("请求出错 %s", err)) - } - // 最后关闭连接 - defer resp.Body.Close() - // 读取内容 - respBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - return httpResponse, errors.New(fmt.Sprintf("解析内容出错 %s", err)) - } - httpResponse.Status = resp.Status - httpResponse.StatusCode = resp.StatusCode - httpResponse.Header = resp.Header - httpResponse.Body = respBody - httpResponse.ContentLength = resp.ContentLength - return httpResponse, err -} - -func GetJsonHeader(url string, params map[string]interface{}, headers goheader.Headers) (httpResponse Response, err error) { - // 创建 http 客户端 - client := &http.Client{} - // 创建请求 - req, _ := http.NewRequest(http.MethodGet, url, nil) - if len(params) > 0 { - // GET 请求携带查询参数 - q := req.URL.Query() - for k, v := range params { - q.Add(k, getString(v)) - } - req.URL.RawQuery = q.Encode() - } - // 设置请求头 - req.Header.Set("User-Agent", gorequest.GetRandomUserAgent()) - req.Header.Set("Content-Type", "application/json") - for key, value := range headers { - req.Header.Set(key, value.(string)) - } - // 发送请求 - resp, err := client.Do(req) - if err != nil { - // 格式化返回错误 - return httpResponse, errors.New(fmt.Sprintf("请求出错 %s", err)) - } - // 最后关闭连接 - defer resp.Body.Close() - // 读取内容 - respBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - return httpResponse, errors.New(fmt.Sprintf("解析内容出错 %s", err)) - } - httpResponse.Status = resp.Status - httpResponse.StatusCode = resp.StatusCode - httpResponse.Header = resp.Header - httpResponse.Body = respBody - httpResponse.ContentLength = resp.ContentLength - return httpResponse, err -} - -func PostForm(targetUrl string, params map[string]interface{}) (httpResponse Response, err error) { - // 创建 http 客户端 - client := &http.Client{} - // 携带 form 参数 - form := url.Values{} - if len(params) > 0 { - for k, v := range params { - form.Add(k, getString(v)) - } - } - // 创建请求 - req, _ := http.NewRequest(http.MethodPost, targetUrl, strings.NewReader(form.Encode())) - // 设置请求头 - req.Header.Set("User-Agent", gorequest.GetRandomUserAgent()) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - // 发送请求 - resp, err := client.Do(req) - if err != nil { - // 格式化返回错误 - return httpResponse, errors.New(fmt.Sprintf("请求出错 %s", err)) - } - // 最后关闭连接 - defer resp.Body.Close() - // 读取内容 - respBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - return httpResponse, errors.New(fmt.Sprintf("解析内容出错 %s", err)) - } - httpResponse.Status = resp.Status - httpResponse.StatusCode = resp.StatusCode - httpResponse.Header = resp.Header - httpResponse.Body = respBody - httpResponse.ContentLength = resp.ContentLength - return httpResponse, err -} - -func PostJson(targetUrl string, paramsStr []byte) (httpResponse Response, err error) { - // 创建请求 - req, _ := http.NewRequest(http.MethodPost, targetUrl, bytes.NewBuffer(paramsStr)) - // 设置请求头 - req.Header.Set("User-Agent", gorequest.GetRandomUserAgent()) - req.Header.Set("Content-Type", "application/json") - // 创建 http 客户端 - client := &http.Client{} - // 发送请求 - resp, err := client.Do(req) - if err != nil { - // 格式化返回错误 - return httpResponse, errors.New(fmt.Sprintf("请求出错 %s", err)) - } - // 最后关闭连接 - defer resp.Body.Close() - // 读取内容 - respBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - return httpResponse, errors.New(fmt.Sprintf("解析内容出错 %s", err)) - } - httpResponse.Status = resp.Status - httpResponse.StatusCode = resp.StatusCode - httpResponse.Header = resp.Header - httpResponse.Body = respBody - httpResponse.ContentLength = resp.ContentLength - return httpResponse, err -} - -func PostXml(targetUrl string, paramsStr []byte) (httpResponse Response, err error) { - // 创建请求 - req, _ := http.NewRequest(http.MethodPost, targetUrl, bytes.NewReader(paramsStr)) - // 设置请求头 - req.Header.Set("User-Agent", gorequest.GetRandomUserAgent()) - // 创建 http 客户端 - client := &http.Client{} - // 发送请求 - resp, err := client.Do(req) - if err != nil { - // 格式化返回错误 - return httpResponse, errors.New(fmt.Sprintf("请求出错 %s", err)) - } - // 最后关闭连接 - defer resp.Body.Close() - // 读取内容 - respBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - return httpResponse, errors.New(fmt.Sprintf("解析内容出错 %s", err)) - } - httpResponse.Status = resp.Status - httpResponse.StatusCode = resp.StatusCode - httpResponse.Header = resp.Header - httpResponse.Body = respBody - httpResponse.ContentLength = resp.ContentLength - return httpResponse, err -} - -func PostJsonHeader(targetUrl string, paramsStr []byte, headers goheader.Headers) (httpResponse Response, err error) { - // 创建请求 - req, _ := http.NewRequest(http.MethodPost, targetUrl, bytes.NewBuffer(paramsStr)) - // 设置请求头 - req.Header.Set("User-Agent", gorequest.GetRandomUserAgent()) - req.Header.Set("Content-Type", "application/json") - for key, value := range headers { - req.Header.Set(key, value.(string)) - } - // 创建 http 客户端 - client := &http.Client{} - // 发送请求 - resp, err := client.Do(req) - if err != nil { - // 格式化返回错误 - return httpResponse, errors.New(fmt.Sprintf("请求出错 %s", err)) - } - // 最后关闭连接 - defer resp.Body.Close() - // 读取内容 - respBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - return httpResponse, errors.New(fmt.Sprintf("解析内容出错 %s", err)) - } - httpResponse.Status = resp.Status - httpResponse.StatusCode = resp.StatusCode - httpResponse.Header = resp.Header - httpResponse.Body = respBody - httpResponse.ContentLength = resp.ContentLength - return httpResponse, err -} - -func PostCert(targetUrl string, params io.Reader, p12Cert *tls.Certificate) (httpResponse Response, err error) { - if p12Cert == nil { - return httpResponse, errors.New("need p12Cert") - } - transport := &http.Transport{ - TLSClientConfig: &tls.Config{ - Certificates: []tls.Certificate{*p12Cert}, - }, - DisableCompression: true, - } - // 创建请求 - req, _ := http.NewRequest(http.MethodPost, targetUrl, params) - // 设置请求头 - req.Header.Set("User-Agent", gorequest.GetRandomUserAgent()) - // 创建 http 客户端 - client := &http.Client{ - Transport: transport, - } - // 发送请求 - resp, err := client.Do(req) - if err != nil { - // 格式化返回错误 - return httpResponse, errors.New(fmt.Sprintf("请求出错 %s", err)) - } - // 最后关闭连接 - defer resp.Body.Close() - // 读取内容 - respBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - return httpResponse, errors.New(fmt.Sprintf("解析内容出错 %s", err)) - } - httpResponse.Status = resp.Status - httpResponse.StatusCode = resp.StatusCode - httpResponse.Header = resp.Header - httpResponse.Body = respBody - httpResponse.ContentLength = resp.ContentLength - return httpResponse, err -} - -func getString(i interface{}) string { - switch v := i.(type) { - case string: - return v - case []byte: - return string(v) - case int: - return strconv.Itoa(v) - case bool: - return strconv.FormatBool(v) - default: - marshal, _ := json.Marshal(v) - return string(marshal) - } -} diff --git a/utils/gorequest/gorequest.go b/utils/gorequest/gorequest.go deleted file mode 100644 index 5b2be8c2..00000000 --- a/utils/gorequest/gorequest.go +++ /dev/null @@ -1,114 +0,0 @@ -package gorequest - -import ( - "errors" - "math/rand" - "net" - "net/http" - "runtime" - "strings" - "time" -) - -// ClientIp 尽最大努力实现获取客户端 IP 的算法。 -// 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。 -func ClientIp(r *http.Request) string { - // xForwardedFor - xForwardedFor := r.Header.Get("X-Forwarded-For") - ip := strings.TrimSpace(strings.Split(xForwardedFor, ",")[0]) - if ip != "" { - return ip - } - // xRealIp - ip = strings.TrimSpace(r.Header.Get("X-Real-Ip")) - if ip != "" { - return ip - } - // HTTPCLIENTIP - HTTPCLIENTIP := r.Header.Get("HTTP_CLIENT_IP") - ip = strings.TrimSpace(strings.Split(HTTPCLIENTIP, ",")[0]) - if ip != "" { - return ip - } - // HTTPXFORWARDEDFOR - HTTPXFORWARDEDFOR := r.Header.Get("HTTP_X_FORWARDED_FOR") - ip = strings.TrimSpace(strings.Split(HTTPXFORWARDEDFOR, ",")[0]) - if ip != "" { - return ip - } - // system - if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil { - return ip - } - - return "" -} - -// GetRandomUserAgent 获取用户UA -func GetRandomUserAgent() 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/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/98.0.4758.80 Safari/537.36", // Chrome 2022-02-14 - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:97.0) Gecko/20100101 Firefox/97.0", // Firefox 2022-02-14 -} - -func ExternalIp() (string, error) { - faces, err := net.Interfaces() - if err != nil { - return "", err - } - for _, iface := range faces { - if iface.Flags&net.FlagUp == 0 { - continue // interface down - } - if iface.Flags&net.FlagLoopback != 0 { - continue // loopback interface - } - adders, err := iface.Addrs() - if err != nil { - return "", err - } - for _, addr := range adders { - var ip net.IP - switch v := addr.(type) { - case *net.IPNet: - ip = v.IP - case *net.IPAddr: - ip = v.IP - } - if ip == nil || ip.IsLoopback() { - continue - } - ip = ip.To4() - if ip == nil { - continue // not an ipv4 address - } - return ip.String(), nil - } - } - return "", errors.New("are you connected to the network") -} diff --git a/utils/gorequest/header.go b/utils/gorequest/header.go new file mode 100644 index 00000000..7e6aa783 --- /dev/null +++ b/utils/gorequest/header.go @@ -0,0 +1,58 @@ +package gorequest + +import ( + "net/url" +) + +// Headers 头部信息 +type Headers map[string]string + +// NewHeaders 新建头部信息 +func NewHeaders() Headers { + P := make(Headers) + return P +} + +// NewNewHeadersWith 头部信息使用 +func NewNewHeadersWith(headers ...Headers) Headers { + p := make(Headers) + for _, v := range headers { + p.SetHeaders(v) + } + return p +} + +// Set 设置头部信息 +func (p Headers) Set(key, value string) { + p[key] = value +} + +// SetHeaders 批量设置头部信息 +func (p Headers) SetHeaders(headers Headers) { + for key, value := range headers { + p[key] = value + } +} + +// GetQuery 获取头部信息 +func (p Headers) GetQuery() string { + u := url.Values{} + for k, v := range p { + u.Set(k, v) + } + return u.Encode() +} + +// DeepCopy 深度复制 +func (p *Headers) DeepCopy() map[string]string { + targetMap := make(map[string]string) + + // 从原始复制到目标 + for key, value := range *p { + targetMap[key] = value + } + + // 重新申请一个新的map + *p = map[string]string{} + return targetMap +} diff --git a/utils/gorequest/http.go b/utils/gorequest/http.go new file mode 100644 index 00000000..7a4ef0a9 --- /dev/null +++ b/utils/gorequest/http.go @@ -0,0 +1,301 @@ +package gorequest + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "errors" + "fmt" + "go.dtapp.net/gotime" + "io" + "io/ioutil" + "net/http" + "net/url" + "runtime" + "strings" + "time" +) + +var userAgentFormat = "DtApp-Request/%s GO/%s" + +// Response 返回内容 +type Response struct { + RequestUri string //【请求】链接 + RequestParams Params //【请求】参数 + RequestMethod string //【请求】方式 + RequestHeader Headers //【请求】头部 + RequestTime time.Time //【请求】时间 + ResponseHeader http.Header //【返回】头部 + ResponseStatus string //【返回】状态 + ResponseStatusCode int //【返回】状态码 + ResponseBody []byte //【返回】内容 + ResponseContentLength int64 //【返回】大小 + ResponseTime time.Time //【返回】时间 +} + +// App 实例 +type App struct { + Uri string // 全局请求地址,没有设置url才会使用 + Error error // 错误 + httpUri string // 请求地址 + httpMethod string // 请求方法 + httpHeader Headers // 请求头 + httpParams Params // 请求参数 + responseContent Response // 返回内容 + httpContentType string // 请求内容类型 + debug bool // 是否开启调试模式 + p12Cert *tls.Certificate // p12证书内容 +} + +// 定义 +var ( + httpParamsModeJson = "JSON" + httpParamsModeXml = "XML" + httpParamsModeForm = "FORM" +) + +// NewHttp 实例化 +func NewHttp() *App { + return &App{ + httpHeader: NewHeaders(), + httpParams: NewParams(), + } +} + +// SetDebug 设置调试模式 +func (app *App) SetDebug() { + app.debug = true +} + +// SetUri 设置请求地址 +func (app *App) SetUri(uri string) { + app.httpUri = uri +} + +// 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.httpContentType = httpParamsModeJson +} + +// SetContentTypeForm 设置FORM格式 +func (app *App) SetContentTypeForm() { + app.httpContentType = httpParamsModeForm +} + +// SetContentTypeXml 设置XML格式 +func (app *App) SetContentTypeXml() { + app.httpContentType = httpParamsModeXml +} + +// SetParam 设置请求参数 +func (app *App) SetParam(key string, value interface{}) { + if key == "" { + panic("url is empty") + } + app.httpParams.Set(key, value) +} + +// SetParams 批量设置请求参数 +func (app *App) SetParams(params Params) { + for key, value := range params { + app.httpParams.Set(key, value) + } +} + +// SetP12Cert 设置证书 +func (app *App) SetP12Cert(content *tls.Certificate) { + app.p12Cert = content +} + +// Get 发起GET请求 +func (app *App) Get(uri ...string) (httpResponse Response, err error) { + if len(uri) == 1 { + app.Uri = uri[0] + } + // 设置请求方法 + app.httpMethod = http.MethodGet + return request(app) +} + +// Post 发起POST请求 +func (app *App) Post(uri ...string) (httpResponse Response, err error) { + if len(uri) == 1 { + app.Uri = uri[0] + } + // 设置请求方法 + 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) { + + // 赋值 + httpResponse.RequestTime = gotime.Current().Time + httpResponse.RequestUri = app.httpUri + httpResponse.RequestMethod = app.httpMethod + httpResponse.RequestParams = app.httpParams.DeepCopy() + httpResponse.RequestHeader = app.httpHeader.DeepCopy() + + // 判断网址 + if httpResponse.RequestUri == "" { + httpResponse.RequestUri = app.Uri + } + if httpResponse.RequestUri == "" { + app.Error = errors.New("没有设置Uri") + return httpResponse, app.Error + } + + // 创建 http 客户端 + client := &http.Client{} + + if app.p12Cert != nil { + transport := &http.Transport{ + TLSClientConfig: &tls.Config{ + Certificates: []tls.Certificate{*app.p12Cert}, + }, + DisableCompression: true, + } + client = &http.Client{ + Transport: transport, + } + } + + httpResponse.RequestHeader.Set("Sdk-User-Agent", fmt.Sprintf(userAgentFormat, runtime.GOOS, runtime.Version())) + switch app.httpContentType { + case httpParamsModeJson: + httpResponse.RequestHeader.Set("Content-Type", "application/json") + case httpParamsModeForm: + httpResponse.RequestHeader.Set("Content-Type", "application/x-www-form-urlencoded") + case httpParamsModeXml: + httpResponse.RequestHeader.Set("Content-Type", "text/xml") + } + + // 请求内容 + var reqBody io.Reader + + if httpResponse.RequestMethod == http.MethodPost && app.httpContentType == httpParamsModeJson { + jsonStr, err := json.Marshal(httpResponse.RequestParams) + if err != nil { + app.Error = errors.New(fmt.Sprintf("解析出错 %s", err)) + return httpResponse, app.Error + } + // 赋值 + reqBody = bytes.NewBuffer(jsonStr) + } + + if httpResponse.RequestMethod == http.MethodPost && app.httpContentType == httpParamsModeForm { + // 携带 form 参数 + form := url.Values{} + if len(httpResponse.RequestParams) > 0 { + for k, v := range httpResponse.RequestParams { + form.Add(k, GetParamsString(v)) + } + } + // 赋值 + reqBody = strings.NewReader(form.Encode()) + } + + if app.httpContentType == httpParamsModeXml { + reqBody, err = httpResponse.RequestParams.MarshalXML() + if err != nil { + app.Error = errors.New(fmt.Sprintf("解析XML出错 %s", err)) + return httpResponse, app.Error + } + } + + // 创建请求 + req, err := http.NewRequest(httpResponse.RequestMethod, httpResponse.RequestUri, reqBody) + if err != nil { + app.Error = errors.New(fmt.Sprintf("创建请求出错 %s", err)) + return httpResponse, app.Error + } + + // GET 请求携带查询参数 + if httpResponse.RequestMethod == http.MethodGet { + if len(httpResponse.RequestParams) > 0 { + q := req.URL.Query() + for k, v := range httpResponse.RequestParams { + q.Add(k, GetParamsString(v)) + } + req.URL.RawQuery = q.Encode() + } + } + + // 设置请求头 + if len(httpResponse.RequestHeader) > 0 { + for key, value := range httpResponse.RequestHeader { + req.Header.Set(key, value) + } + } + + // 发送请求 + resp, err := client.Do(req) + if err != nil { + app.Error = errors.New(fmt.Sprintf("请求出错 %s", err)) + return httpResponse, app.Error + } + + // 最后关闭连接 + defer resp.Body.Close() + + // 读取内容 + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + app.Error = errors.New(fmt.Sprintf("解析内容出错 %s", err)) + return httpResponse, app.Error + } + + // 赋值 + httpResponse.ResponseTime = gotime.Current().Time + httpResponse.ResponseStatus = resp.Status + httpResponse.ResponseStatusCode = resp.StatusCode + httpResponse.ResponseHeader = resp.Header + httpResponse.ResponseBody = body + httpResponse.ResponseContentLength = resp.ContentLength + + if app.debug == true { + fmt.Printf("gorequest:%+v\n", httpResponse) + fmt.Printf("gorequest.body:%s\n", httpResponse.ResponseBody) + } + + return httpResponse, err +} diff --git a/utils/gorequest/ip.go b/utils/gorequest/ip.go new file mode 100644 index 00000000..d7811a90 --- /dev/null +++ b/utils/gorequest/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/utils/gorequest/params.go b/utils/gorequest/params.go new file mode 100644 index 00000000..289dc616 --- /dev/null +++ b/utils/gorequest/params.go @@ -0,0 +1,68 @@ +package gorequest + +import ( + "encoding/json" + "go.dtapp.net/gostring" + "log" +) + +// Params 参数 +type Params map[string]interface{} + +// NewParams 新建参数 +func NewParams() Params { + P := make(Params) + return P +} + +// NewParamsWith 参数使用 +func NewParamsWith(params ...Params) Params { + p := make(Params) + for _, v := range params { + p.SetParams(v) + } + return p +} + +// Set 设置参数 +func (p Params) Set(key string, value interface{}) { + p[key] = value +} + +// SetParams 批量设置参数 +func (p Params) SetParams(params Params) { + for key, value := range params { + p[key] = value + } +} + +// GetParamsString 获取参数字符串 +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 gostring.ToString(src) + } + data, err := json.Marshal(src) + if err != nil { + log.Fatal(err) + } + return string(data) +} + +// DeepCopy 深度复制 +func (p *Params) DeepCopy() map[string]interface{} { + targetMap := make(map[string]interface{}) + + // 从原始复制到目标 + for key, value := range *p { + targetMap[key] = value + } + + // 重新申请一个新的map + *p = map[string]interface{}{} + return targetMap +} diff --git a/utils/gorequest/url.go b/utils/gorequest/url.go new file mode 100644 index 00000000..0d3ad79f --- /dev/null +++ b/utils/gorequest/url.go @@ -0,0 +1,70 @@ +package gorequest + +import ( + "net/url" + "strings" +) + +// ResponseUrlParse 返回参数 +type ResponseUrlParse struct { + Uri string `json:"uri"` // URI + Urn string `json:"urn"` // URN + Url string `json:"url"` // URL + Scheme string `json:"scheme"` // 协议 + Host string `json:"host"` // 主机 + Hostname string `json:"hostname"` // 主机名 + Port string `json:"port"` // 端口 + Path string `json:"path"` // 路径 + RawQuery string `json:"raw_query"` // 参数 ? + Fragment string `json:"fragment"` // 片段 # +} + +// UriParse 解析URl +func UriParse(input string) (resp ResponseUrlParse) { + parse, err := url.Parse(input) + if err != nil { + return + } + resp.Uri = input + resp.Urn = parse.Host + parse.Path + resp.Url = parse.Scheme + "://" + parse.Host + parse.Path + resp.Scheme = parse.Scheme + resp.Host = parse.Host + resp.Hostname = parse.Hostname() + resp.Port = parse.Port() + resp.Path = parse.Path + resp.RawQuery = parse.RawQuery + resp.Fragment = parse.Fragment + return +} + +// UriFilterExcludeQueryString 过滤掉url中的参数 +func UriFilterExcludeQueryString(uri string) string { + URL, _ := url.Parse(uri) + clearUri := strings.ReplaceAll(uri, URL.RawQuery, "") + clearUri = strings.TrimRight(clearUri, "?") + return strings.TrimRight(clearUri, "/") +} + +// LenCode 编码 +func LenCode(s string) string { + escape := url.QueryEscape(s) + return escape +} + +// DeCode 解码 +func DeCode(s string) string { + unescape, _ := url.QueryUnescape(s) + return unescape +} + +// ParseQuery 获取URL参数 https://studygolang.com/articles/2876 +func ParseQuery(s string) map[string][]string { + u, err := url.Parse(s) + if err != nil { + return nil + } + urlParam := u.RawQuery + m, _ := url.ParseQuery(urlParam) + return m +} diff --git a/utils/gorequest/user_agent.go b/utils/gorequest/user_agent.go new file mode 100644 index 00000000..8880373b --- /dev/null +++ b/utils/gorequest/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("Go-dta-request/%v", content) +} diff --git a/utils/gorequest/xml.go b/utils/gorequest/xml.go new file mode 100644 index 00000000..3c1d272c --- /dev/null +++ b/utils/gorequest/xml.go @@ -0,0 +1,47 @@ +package gorequest + +import ( + "bytes" + "encoding/xml" + "fmt" + "io" +) + +// MarshalXML 结构体转xml +func (p Params) MarshalXML() (reader io.Reader, err error) { + buffer := bytes.NewBuffer(make([]byte, 0)) + + if _, err = io.WriteString(buffer, ""); err != nil { + return + } + + for k, v := range p { + switch { + case k == "detail": + if _, err = io.WriteString(buffer, ""); err != nil { + return + } + default: + if _, err = io.WriteString(buffer, "<"+k+">"); err != nil { + return + } + if err = xml.EscapeText(buffer, []byte(fmt.Sprintf("%v", v))); err != nil { + return + } + if _, err = io.WriteString(buffer, ""); err != nil { + return + } + } + } + + if _, err = io.WriteString(buffer, ""); err != nil { + return + } + return buffer, nil +}