Golang封装一个request类支持socks和http代理
1. 需要需用国外服务器做代理的时候
2. 需要使用代理服务器做白名单的时候
3. 代码还支持重试机制
封装代码如下
package utilsimport ("bytes""crypto/tls""errors""fmt""io/ioutil""mime/multipart""net/http""net/url""strings""time""golang.org/x/net/proxy"
)type SendRequest struct {client *http.ClientretryNum int // 重试次数retryTime int // 重试间隔时间headers http.Headerboundary string
}func NewSendRequest(headers http.Header, boundary string) *SendRequest {if headers == nil {headers = http.Header{}headers.Set("Content-Type", "application/x-www-form-urlencoded")}return &SendRequest{client: &http.Client{Timeout: 30 * time.Second,},retryTime: 10,headers: headers,boundary: boundary,}
}func (s *SendRequest) SetHeaders(headers map[string]string) {// 设置请求头for key, value := range headers {s.headers.Set(key, value)}
}func (s *SendRequest) SetProxy(proxyAddr string) {// 创建代理 URLproxyURL, err := url.Parse(proxyAddr)if err != nil {fmt.Println("Failed to parse proxy URL:", err)return}var transport *http.Transportif strings.Contains(proxyAddr, "socks") {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,}} else {// 创建自定义的 Transporttransport = &http.Transport{Proxy: http.ProxyURL(proxyURL),TLSClientConfig: &tls.Config{InsecureSkipVerify: true,},}}s.client.Transport = transport
}func (s *SendRequest) send(method string, url string, param url.Values, headers http.Header) ([]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())}req, err := http.NewRequest(method, url, reqBody)if err != nil {return nil, nil, err}// 设置请求头if headers != nil && 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()body, err := ioutil.ReadAll(resp.Body)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, errors.New(fmt.Sprintf("状态码:%d", resp.StatusCode))}return body, resp, nil
}func (s *SendRequest) Post(url string, param url.Values) ([]byte, *http.Response, error) {return s.send("POST", url, param, 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 mainimport ("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.topbody, _, err := sendRequest.Get("https://myip.top", nil)if err != nil {log.Fatal(err)}log.Println(string(body))
}
当然可以自己搭建一个socks5和http的代理服务器
自己搭建代码如下:
package mainimport ("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