368 lines
10 KiB
Go
368 lines
10 KiB
Go
|
|
package httputils
|
|||
|
|
|
|||
|
|
// http request 工具函数
|
|||
|
|
import (
|
|||
|
|
"crypto/tls"
|
|||
|
|
"errors"
|
|||
|
|
"fmt"
|
|||
|
|
"io/ioutil"
|
|||
|
|
"log"
|
|||
|
|
"net"
|
|||
|
|
"net/http"
|
|||
|
|
"net/url"
|
|||
|
|
"strings"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"github.com/bytedance/sonic"
|
|||
|
|
"github.com/valyala/fasthttp"
|
|||
|
|
"golang.org/x/net/proxy"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
var (
|
|||
|
|
fastHttpClient = &fasthttp.Client{
|
|||
|
|
Name: "http",
|
|||
|
|
MaxConnsPerHost: 10000,
|
|||
|
|
MaxIdleConnDuration: 30 * time.Second,
|
|||
|
|
ReadTimeout: 50 * time.Second,
|
|||
|
|
WriteTimeout: 50 * time.Second,
|
|||
|
|
TLSConfig: &tls.Config{InsecureSkipVerify: true}, // 跳过证书验证
|
|||
|
|
}
|
|||
|
|
clientHuoBi *http.Client // 火币交易所 HTTP 客户端
|
|||
|
|
clientBinance *http.Client // 币安交易所 HTTP 客户端
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
func init() {
|
|||
|
|
// 克隆默认的 HTTP 传输配置
|
|||
|
|
t := http.DefaultTransport.(*http.Transport).Clone()
|
|||
|
|
t.MaxIdleConns = 100
|
|||
|
|
t.MaxConnsPerHost = 10000
|
|||
|
|
t.MaxIdleConnsPerHost = 100
|
|||
|
|
t.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} // 跳过证书验证
|
|||
|
|
|
|||
|
|
// 初始化火币交易所 HTTP 客户端
|
|||
|
|
clientHuoBi = &http.Client{
|
|||
|
|
Timeout: 50 * time.Second, // 请求超时时间
|
|||
|
|
Transport: t,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 初始化币安交易所 HTTP 客户端
|
|||
|
|
clientBinance = &http.Client{
|
|||
|
|
Timeout: 50 * time.Second, // 请求超时时间
|
|||
|
|
Transport: t,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
初始化请求代理
|
|||
|
|
- @proxy 代理地址(http) ip:port
|
|||
|
|
*/
|
|||
|
|
func InitProxy(proxy string) {
|
|||
|
|
if proxy != "" {
|
|||
|
|
fastHttpClient.Dial = createHTTPProxyDialer(proxy) // 设置代理拨号器
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// net http 请求(币安)
|
|||
|
|
func NewHttpRequestBinance(reqMethod, reqUrl, postData string, reqHeaders map[string]string) ([]byte, error) {
|
|||
|
|
req, _ := http.NewRequest(reqMethod, reqUrl, strings.NewReader(postData)) // 创建新的 HTTP 请求
|
|||
|
|
if req.Header.Get("User-Agent") == "" {
|
|||
|
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36") // 设置用户代理
|
|||
|
|
}
|
|||
|
|
if reqHeaders != nil {
|
|||
|
|
for k, v := range reqHeaders {
|
|||
|
|
req.Header.Add(k, v) // 添加请求头
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
resp, err := clientBinance.Do(req) // 发送请求
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
defer resp.Body.Close() // 确保关闭响应体
|
|||
|
|
|
|||
|
|
bodyData, err := ioutil.ReadAll(resp.Body) // 读取响应体
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
arr := make([]byte, len(bodyData))
|
|||
|
|
copy(arr, bodyData)
|
|||
|
|
|
|||
|
|
if resp.StatusCode != 200 { // 检查响应状态码
|
|||
|
|
return nil, errors.New(string(arr))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return arr, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// fast http 执行请求
|
|||
|
|
func NewHttpRequestWithFasthttp(reqMethod, reqUrl, postData string, headers map[string]string) ([]byte, error) {
|
|||
|
|
req := fasthttp.AcquireRequest() // 从 fasthttp 获取请求
|
|||
|
|
resp := fasthttp.AcquireResponse() // 从 fasthttp 获取响应
|
|||
|
|
defer func() {
|
|||
|
|
fasthttp.ReleaseRequest(req) // 释放请求
|
|||
|
|
fasthttp.ReleaseResponse(resp) // 释放响应
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
for k, v := range headers {
|
|||
|
|
req.Header.Set(k, v) // 设置请求头
|
|||
|
|
}
|
|||
|
|
req.Header.SetMethod(reqMethod) // 设置请求方法
|
|||
|
|
req.SetRequestURI(reqUrl) // 设置请求 URL
|
|||
|
|
req.SetBodyString(postData) // 设置请求体
|
|||
|
|
|
|||
|
|
err := fastHttpClient.Do(req, resp) // 执行请求
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
recbody := resp.Body() // 获取响应体
|
|||
|
|
arr := make([]byte, len(recbody))
|
|||
|
|
copy(arr, recbody)
|
|||
|
|
|
|||
|
|
if resp.StatusCode() != 200 { // 检查响应状态码
|
|||
|
|
return nil, errors.New(fmt.Sprintf("HttpStatusCode:%d ,Desc:%s", resp.StatusCode(), string(recbody)))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return recbody, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HTTP GET 请求,返回 map
|
|||
|
|
func HttpGet(reqUrl string) (map[string]interface{}, error) {
|
|||
|
|
respData, err := NewHttpRequestWithFasthttp("GET", reqUrl, "", nil) // 发送 GET 请求
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var bodyDataMap map[string]interface{}
|
|||
|
|
err = sonic.Unmarshal(respData, &bodyDataMap) // 解析 JSON 响应
|
|||
|
|
if err != nil {
|
|||
|
|
log.Println(string(respData)) // 打印响应数据
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return bodyDataMap, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HTTP GET 请求,带请求头
|
|||
|
|
func HttpGet2(reqUrl string, headers map[string]string) (map[string]interface{}, error) {
|
|||
|
|
if headers == nil {
|
|||
|
|
headers = map[string]string{}
|
|||
|
|
}
|
|||
|
|
headers["Content-Type"] = "application/x-www-form-urlencoded" // 设置内容类型
|
|||
|
|
respData, err := NewHttpRequestWithFasthttp("GET", reqUrl, "", headers) // 发送 GET 请求
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var bodyDataMap map[string]interface{}
|
|||
|
|
err = sonic.Unmarshal(respData, &bodyDataMap) // 解析 JSON 响应
|
|||
|
|
if err != nil {
|
|||
|
|
log.Println("respData", string(respData)) // 打印响应数据
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return bodyDataMap, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HTTP GET 请求,返回接口切片
|
|||
|
|
func HttpGet3(reqUrl string, headers map[string]string) ([]interface{}, error) {
|
|||
|
|
if headers == nil {
|
|||
|
|
headers = map[string]string{}
|
|||
|
|
}
|
|||
|
|
headers["Content-Type"] = "application/x-www-form-urlencoded" // 设置内容类型
|
|||
|
|
respData, err := NewHttpRequestWithFasthttp("GET", reqUrl, "", headers) // 发送 GET 请求
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
var bodyDataMap []interface{}
|
|||
|
|
err = sonic.Unmarshal(respData, &bodyDataMap) // 解析 JSON 响应
|
|||
|
|
if err != nil {
|
|||
|
|
log.Println("respData", string(respData)) // 打印响应数据
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return bodyDataMap, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HTTP GET 请求,结果存储在 result 中
|
|||
|
|
func HttpGet4(reqUrl string, headers map[string]string, result interface{}) error {
|
|||
|
|
if headers == nil {
|
|||
|
|
headers = map[string]string{}
|
|||
|
|
}
|
|||
|
|
headers["Content-Type"] = "application/x-www-form-urlencoded" // 设置内容类型
|
|||
|
|
respData, err := NewHttpRequestWithFasthttp("GET", reqUrl, "", headers) // 发送 GET 请求
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
err = sonic.Unmarshal(respData, result) // 解析 JSON 响应
|
|||
|
|
if err != nil {
|
|||
|
|
log.Printf("HttpGet4 - json.Unmarshal failed : %v, resp %s", err, string(respData))
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HTTP GET 请求,返回原始字节
|
|||
|
|
func HttpGet5(reqUrl string, headers map[string]string) ([]byte, error) {
|
|||
|
|
if headers == nil {
|
|||
|
|
headers = map[string]string{}
|
|||
|
|
}
|
|||
|
|
headers["Content-Type"] = "application/x-www-form-urlencoded" // 设置内容类型
|
|||
|
|
respData, err := NewHttpRequestWithFasthttp("GET", reqUrl, "", headers) // 发送 GET 请求
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return respData, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HTTP POST 请求,表单数据
|
|||
|
|
func HttpPostForm(reqUrl string, postData url.Values) ([]byte, error) {
|
|||
|
|
respData, err := NewHttpRequestWithFasthttp("POST", reqUrl, postData.Encode(), nil) // 发送 POST 请求
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return respData, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HTTP POST 请求,返回 map
|
|||
|
|
func HttpPost(reqUrl string, postData string) (map[string]interface{}, error) {
|
|||
|
|
respData, err := NewHttpRequestWithFasthttp("POST", reqUrl, postData, nil) // 发送 POST 请求
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var bodyDataMap map[string]interface{}
|
|||
|
|
err = sonic.Unmarshal(respData, &bodyDataMap) // 解析 JSON 响应
|
|||
|
|
if err != nil {
|
|||
|
|
log.Println(string(respData)) // 打印响应数据
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return bodyDataMap, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HTTP POST 请求,返回原始字节
|
|||
|
|
func HttpPost2(reqUrl string, postData string) ([]byte, error) {
|
|||
|
|
respData, err := NewHttpRequestWithFasthttp("POST", reqUrl, postData, nil) // 发送 POST 请求
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return respData, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HTTP POST 请求,返回接口切片
|
|||
|
|
func HttpPost3(reqUrl string, postData string) ([]interface{}, error) {
|
|||
|
|
respData, err := NewHttpRequestWithFasthttp("POST", reqUrl, postData, nil) // 发送 POST 请求
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var bodyDataMap []interface{}
|
|||
|
|
err = sonic.Unmarshal(respData, &bodyDataMap) // 解析 JSON 响应
|
|||
|
|
if err != nil {
|
|||
|
|
log.Println(string(respData)) // 打印响应数据
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return bodyDataMap, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HTTP POST 请求,结果存储在 result 中
|
|||
|
|
func HttpPost4(reqUrl string, postData string, result interface{}) error {
|
|||
|
|
respData, err := NewHttpRequestWithFasthttp("POST", reqUrl, postData, nil) // 发送 POST 请求
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
err = sonic.Unmarshal(respData, result) // 解析 JSON 响应
|
|||
|
|
if err != nil {
|
|||
|
|
log.Printf("HttpPost4 - json.Unmarshal failed : %v, resp %s", err, string(respData))
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HTTP POST 请求,返回原始字节
|
|||
|
|
func HttpPost5(reqUrl string, postData string) ([]byte, error) {
|
|||
|
|
respData, err := NewHttpRequestWithFasthttp("POST", reqUrl, postData, nil) // 发送 POST 请求
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return respData, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HTTP POST 请求,表单数据,带请求头
|
|||
|
|
func HttpPostForm2(reqUrl string, postData url.Values, headers map[string]string) ([]byte, error) {
|
|||
|
|
respData, err := NewHttpRequestWithFasthttp("POST", reqUrl, postData.Encode(), headers) // 发送 POST 请求
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return respData, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建 HTTP 代理拨号器
|
|||
|
|
func createHTTPProxyDialer(proxy string) fasthttp.DialFunc {
|
|||
|
|
// 解析代理 URL
|
|||
|
|
proxyURL, err := url.Parse(proxy)
|
|||
|
|
if err != nil {
|
|||
|
|
log.Fatal(err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 返回拨号器函数
|
|||
|
|
return func(addr string) (net.Conn, error) {
|
|||
|
|
|
|||
|
|
// 选择代理协议
|
|||
|
|
switch proxyURL.Scheme {
|
|||
|
|
case "http", "https":
|
|||
|
|
proxyConn, err := net.Dial("tcp", proxyURL.Host)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Send the HTTP CONNECT request to the proxy
|
|||
|
|
_, err = proxyConn.Write([]byte("CONNECT " + addr + " HTTP/1.1\r\nHost: " + addr + "\r\n\r\n"))
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Read the response from the proxy
|
|||
|
|
buf := make([]byte, 4096)
|
|||
|
|
n, err := proxyConn.Read(buf)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Check for a successful response (HTTP 200)
|
|||
|
|
if !isConnectSuccess(buf[:n]) {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return proxyConn, nil
|
|||
|
|
case "socks5":
|
|||
|
|
return socks5Dial(proxyURL.Host)
|
|||
|
|
default:
|
|||
|
|
return nil, fmt.Errorf("不支持的代理协议: %s", proxyURL.Scheme)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func isConnectSuccess(response []byte) bool {
|
|||
|
|
return len(response) > 0 && strings.HasPrefix(string(response), "HTTP/1.1 200")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// socks5Dial 使用 SOCKS5 代理拨号
|
|||
|
|
func socks5Dial(proxyAddr string) (net.Conn, error) {
|
|||
|
|
// 创建 SOCKS5 代理拨号器
|
|||
|
|
dialer, err := proxy.SOCKS5("tcp", proxyAddr, nil, proxy.Direct)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 使用代理拨号
|
|||
|
|
return dialer.Dial("tcp", "destination_address:port") // 替换为目标地址和端口
|
|||
|
|
}
|