Golang封装一个request类支持socks和http代理

Golang封装一个request类支持socks和http代理

1. 需要需用国外服务器做代理的时候
2. 需要使用代理服务器做白名单的时候
3. 代码还支持重试机制

封装代码如下

package util

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"

	"golang.org/x/net/proxy"
)

const (
	ContentTypeFormData = 0
	ContentTypeJson     = 1
)

type SendRequest struct {
	client    *http.Client
	retryNum  int // 重试次数
	retryTime int // 重试间隔时间
	headers   http.Header
	boundary  string
	Lock      sync.Mutex
}

func NewSendRequest(contentType int) *SendRequest {
	headers := http.Header{}
	if contentType == ContentTypeFormData {
		headers.Set("Content-Type", "application/x-www-form-urlencoded")
	} else if contentType == ContentTypeJson {
		headers.Set("Content-Type", "application/json")
	}
	return &SendRequest{
		client: &http.Client{
			Timeout: 30 * time.Second,
		},
		retryTime: 10,
		headers:   headers,
	}
}

func (s *SendRequest) SetBoundary(_boundary string) *SendRequest {
	s.boundary = _boundary
	return s
}

func (s *SendRequest) SetHeaders(headers http.Header) *SendRequest {
	s.headers = headers
	return s
}

func (s *SendRequest) UpdateHeaders(headers map[string]string) *SendRequest {
	s.Lock.Lock()
	defer s.Lock.Unlock()
	// 设置请求头
	for key, value := range headers {
		s.headers.Set(key, value)
	}
	return s
}

func (s *SendRequest) SetProxy(proxyAddr string) {
	// 创建代理 URL
	proxyURL, err := url.Parse(proxyAddr)
	if err != nil {
		fmt.Println("Failed to parse proxy URL:", err)
		return
	}
	var transport *http.Transport
	if strings.Contains(proxyAddr, "sock") {
		dialer, err := proxy.FromURL(proxyURL, proxy.Direct)
		if err != nil {
			fmt.Println("Failed to create proxy dialer:", err)
			return
		}

		// 创建自定义的 HTTP 客户端,使用 SOCKS5 代理进行请求
		transport = &http.Transport{
			Dial: dialer.Dial,
		}

		// proxy := func(_ *http.Request) (*url.URL, error) {
		// 	return url.Parse(proxyAddr)
		// }
		// transport = &http.Transport{
		// 	Proxy: proxy,
		// }
	} else {
		// 创建自定义的 Transport
		transport = &http.Transport{
			Proxy: http.ProxyURL(proxyURL),
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		}
	}

	s.client.Transport = transport
}

func (s *SendRequest) send(method string, url string, reqBody io.Reader, headers http.Header) ([]byte, *http.Response, error) {
	req, err := http.NewRequest(method, url, reqBody)
	if err != nil {
		return nil, nil, err
	}

	// 设置请求头
	if len(headers) > 0 {
		req.Header = headers
	} else {
		req.Header = s.headers
	}

	resp, err := s.client.Do(req)
	if err != nil {
		return nil, nil, err
	}
	defer resp.Body.Close()

	// s.Lock.Lock()
	body, err := io.ReadAll(resp.Body)
	// s.Lock.Unlock()
	if err != nil {
		return nil, nil, err
	}

	if resp.StatusCode != http.StatusOK {
		// return nil, nil, errors.New(fmt.Sprintf("状态码:%d,内容:%s", resp.StatusCode, string(body)))
		return nil, nil, fmt.Errorf("状态码:%d", resp.StatusCode)
	}

	return body, resp, nil
}

func (s *SendRequest) Post(url string, param url.Values) ([]byte, *http.Response, error) {
	reqBody := strings.NewReader(param.Encode())
	// 设置请求参数
	if s.boundary != "" {
		// 创建请求体
		buf := &bytes.Buffer{}
		writer := multipart.NewWriter(buf)
		// 设置分割符号(boundary)
		writer.SetBoundary(s.boundary)
		// 添加表单字段到请求体
		for key, value := range param {
			for _, v := range value {
				_ = writer.WriteField(key, v)
			}
		}
		// 关闭 multipart.Writer,以写入结尾标识符
		_ = writer.Close()
		reqBody = strings.NewReader(buf.String())
	}

	return s.send("POST", url, reqBody, nil)
}

func (s *SendRequest) PostJSON(url string, data []byte) ([]byte, *http.Response, error) {
	var reqBody *bytes.Reader
	if data != nil {
		reqBody = bytes.NewReader(data)
	}
	return s.send("POST", url, reqBody, nil)
}

func (s *SendRequest) RepeatPost(url string, param url.Values) ([]byte, *http.Response, error) {
	// fmt.Printf("[%s][%d]请求地址:%s\n", uuid, num, url)
	// fmt.Printf("[%s][%d]本次发送:%v\n", uuid, num, param)
	result, resp, err := s.Post(url, param)
	if err != nil && s.retryNum < 5 {
		time.Sleep(time.Second * time.Duration(s.retryTime))
		// fmt.Printf("[%s][%d]请求返回错误:%v\n", uuid, num, err)
		s.retryNum++
		s.retryNum = s.retryNum * 2
		// 进行重发
		return s.RepeatPost(url, param)
	}
	return result, resp, err
}

func (s *SendRequest) Get(url string, headers http.Header) ([]byte, *http.Response, error) {
	return s.send("GET", url, nil, headers)
}

// func main() {
// 	req := NewSendRequest()

// 	// 测试 POST 请求
// 	postURL := "http://example.com/api"
// 	postParam := url.Values{
// 		"key1": []string{"value1"},
// 		"key2": []string{"value2"},
// 	}
// 	postHeaders := map[string]string{
// 		"Content-Type": "application/x-www-form-urlencoded",
// 	}
// 	postResult, err := req.Post(postURL, postParam, postHeaders)
// 	if err != nil {
// 		fmt.Println("POST 请求错误:", err)
// 	} else {
// 		fmt.Println("POST 请求结果:", postResult)
// 	}

// 	// 测试重复发送 POST 请求
// 	repeatUUID := "12345"
// 	repeatURL := "http://example.com/api"
// 	repeatParam := url.Values{
// 		"key1": []string{"value1"},
// 		"key2": []string{"value2"},
// 	}
// 	repeatTimeout := 0 * time.Second
// 	repeatNum := 1
// 	repeatHeaders := map[string]string{
// 		"Content-Type": "application/x-www-form-urlencoded",
// 	}
// 	req.RepeatPost(repeatUUID, repeatURL, repeatParam, repeatTimeout, repeatNum, repeatHeaders)

// 	// 测试 GET 请求
// 	getURL := "http://example.com/api"
// 	getHeaders := map[string]string{
// 		"Content-Type": "application/x-www-form-urlencoded",
// 	}
// 	getResult, err := req.Get(getURL, getHeaders)
// 	if err != nil {
// 		fmt.Println("GET 请求错误:", err)
// 	} else {
// 		fmt.Println("GET 请求结果:", getResult)
// 	}
// }


使用代理请求

package main

import (
	"log"
	"xxx/utils"
)

func main() {
	// 这个网站有很多代理ip,但是大部分都用不了会超时或者连接拒绝
	// https://geonode.com/free-proxy-list
	// 付费的三方https://ip.huashengdaili.com/
	sendRequest := utils.NewSendRequest(nil, "")
	sendRequest.SetProxy("socks4://169.239.49.118:5678")
	// https://api.ip.sb/ip
	// https://myip.top
	body, _, err := sendRequest.Get("https://myip.top", nil)

	if err != nil {
		log.Fatal(err)
	}
	log.Println(string(body))
}

当然可以自己搭建一个socks5和http的代理服务器

自己搭建代码如下:

package main

import (
	"io"
	"log"
	"net"
	"net/http"
	"os"

	"github.com/armon/go-socks5"
)

func handleRequest(w http.ResponseWriter, r *http.Request) {
	// 建立与后端服务器的连接
	destConn, err := net.Dial("tcp", r.Host)
	if err != nil {
		log.Println("Failed to connect to destination:", err)
		http.Error(w, "Failed to connect to destination", http.StatusInternalServerError)
		return
	}
	defer destConn.Close()

	// 将客户端的请求发送到后端服务器
	err = r.Write(destConn)
	if err != nil {
		log.Println("Failed to send request to destination:", err)
		http.Error(w, "Failed to send request to destination", http.StatusInternalServerError)
		return
	}

	// 将后端服务器的响应返回给客户端
	_, err = io.Copy(w, destConn)
	if err != nil {
		log.Println("Failed to send response to client:", err)
		http.Error(w, "Failed to send response to client", http.StatusInternalServerError)
		return
	}
}

func main() {
	// 创建代理服务器处理程序
	proxyHandler := http.HandlerFunc(handleRequest)

	// 启动HTTPS代理服务器
	go func() {
		log.Println("proxy 8080")
		err := http.ListenAndServeTLS(":8080", "./pem/cert.pem", "./pem/key.pem", proxyHandler)
		if err != nil {
			log.Fatal("Failed to start proxy server:", err)
		}
	}()

	// 启动SOCKS5代理服务器
	socksConf := &socks5.Config{}
	socksServer, err := socks5.New(socksConf)
	if err != nil {
		log.Fatal("Failed to create SOCKS5 server:", err)
	}

	socksListener, err := net.Listen("tcp", ":1080")
	if err != nil {
		log.Fatal("Failed to start SOCKS5 server:", err)
	}

	log.Println("SOCKS5 proxy 1080")
	err = http.Serve(socksListener, socksServer)
	if err != nil {
		log.Fatal("Failed to start SOCKS5 server:", err)
	}
}

证书生成

1. openssl生成参考:https://cloud.tencent.com/developer/article/1548350
2. 在线生成:https://www.lddgo.net/encrypt/ssl

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值