Files
exchange_go/pkg/httputils/httputils.go
2025-02-06 11:14:33 +08:00

368 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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") // 替换为目标地址和端口
}