Golang 隧道代理:net/http 与 resty 四种 IP 控制场景
Go 语言标准库 net/http 和第三方库 resty 实现四种隧道代理场景,Transport.ProxyConnectHeader 原生支持 HTTPS Proxy-Tunnel。
亿牛云技术团队2026年5月29日1 分钟阅读
Go 的代理支持
Go 标准库 net/http 通过 Transport.ProxyConnectHeader 原生支持在 HTTPS CONNECT 阶段注入自定义头——这是 Go 相比 Python requests 的优势所在,无需自定义 Adapter。
环境准备
export PROXY_HOST=t.16yun.cn
export PROXY_PORT=31111
export PROXY_USERNAME=your-username
export PROXY_PASSWORD=your-password
export PROXY_TUNNEL=golang-demo-12345
方案一:net/http 标准库
场景 A:强制切换 IP
package main
import (
"crypto/tls"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
"time"
)
func getenv(key, def string) string {
if v := os.Getenv(key); v != "" { return v }
return def
}
func main() {
host := getenv("PROXY_HOST", "t.16yun.cn")
port := getenv("PROXY_PORT", "31111")
user := getenv("PROXY_USERNAME", "user")
pass := getenv("PROXY_PASSWORD", "password")
proxyURL, _ := url.Parse(fmt.Sprintf("http://%s:%s", host, port))
target := getenv("TARGET_URL", "https://httpbin.org/ip")
for i := 1; i <= 3; i++ {
tr := &http.Transport{
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: &tls.Config{InsecureSkipVerify: false},
DisableKeepAlives: true,
}
client := &http.Client{Transport: tr, Timeout: 15 * time.Second}
req, _ := http.NewRequest("GET", target, nil)
req.Header.Set("Connection", "close")
req.SetBasicAuth(user, pass)
resp, _ := client.Do(req)
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
var data map[string]interface{}
json.Unmarshal(body, &data)
fmt.Printf("请求 %d: %v\n", i, data["origin"])
}
}
场景 B:Keep-Alive 保持相同 IP
// 复用 Transport 和 Client
tr := &http.Transport{
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: &tls.Config{InsecureSkipVerify: false},
DisableKeepAlives: false,
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
}
client := &http.Client{Transport: tr, Timeout: 15 * time.Second}
for i := 1; i <= 3; i++ {
req, _ := http.NewRequest("GET", target, nil)
req.Header.Set("Connection", "keep-alive")
req.SetBasicAuth(user, pass)
resp, _ := client.Do(req)
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
var data map[string]interface{}
json.Unmarshal(body, &data)
fmt.Printf("请求 %d: %v\n", i, data["origin"])
}
场景 C-HTTPS:Proxy-Tunnel 固定 IP(HTTPS 目标)
这是 Go 的核心优势——通过 Transport.ProxyConnectHeader 在 CONNECT 阶段注入头:
tunnelVal := getenv("PROXY_TUNNEL", "golang-demo")
connectHeaders := http.Header{}
connectHeaders.Set("Proxy-Tunnel", tunnelVal)
tr := &http.Transport{
Proxy: http.ProxyURL(proxyURL),
ProxyConnectHeader: connectHeaders, // 这在 CONNECT 阶段发送
DisableKeepAlives: false,
}
client := &http.Client{Transport: tr, Timeout: 15 * time.Second}
for i := 1; i <= 3; i++ {
req, _ := http.NewRequest("GET", "https://httpbin.org/ip", nil)
resp, _ := client.Do(req)
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
var data map[string]interface{}
json.Unmarshal(body, &data)
fmt.Printf("请求 %d: %v\n", i, data["origin"])
}
ProxyConnectHeader是 Go net/http 标准库提供的能力,所有基于 net/http 的库(resty、go-resty)都可以通过底层 Transport 使用。
方案二:resty 第三方库
resty 是基于 net/http 的 HTTP 客户端库,API 更简洁。代理场景同样通过底层 Transport 控制:
package main
import (
"crypto/tls"
"fmt"
"net/http"
"net/url"
"os"
"time"
"github.com/go-resty/resty/v2"
)
func getenv(key, def string) string {
if v := os.Getenv(key); v != "" { return v }
return def
}
func main() {
host := getenv("PROXY_HOST", "t.16yun.cn")
port := getenv("PROXY_PORT", "31111")
user := getenv("PROXY_USERNAME", "user")
pass := getenv("PROXY_PASSWORD", "password")
proxyURL, _ := url.Parse(fmt.Sprintf("http://%s:%s@%s:%s", user, pass, host, port))
// 场景 A:强制切换
for i := 1; i <= 3; i++ {
client := resty.New()
client.SetProxy(proxyURL.String())
client.SetTransport(&http.Transport{
DisableKeepAlives: true,
})
resp, _ := client.R().Get("https://httpbin.org/ip")
fmt.Printf("A-%d: %s\n", i, resp.String())
}
// 场景 B:Keep-Alive
client := resty.New()
client.SetProxy(proxyURL.String())
client.SetTransport(&http.Transport{
DisableKeepAlives: false,
MaxIdleConns: 10,
})
for i := 1; i <= 3; i++ {
resp, _ := client.R().Get("https://httpbin.org/ip")
fmt.Printf("B-%d: %s\n", i, resp.String())
}
// 场景 C-HTTPS:Proxy-Tunnel
tunnelVal := getenv("PROXY_TUNNEL", "resty-demo")
client2 := resty.New()
client2.SetTransport(&http.Transport{
Proxy: http.ProxyURL(proxyURL),
ProxyConnectHeader: http.Header{
"Proxy-Tunnel": []string{tunnelVal},
},
DisableKeepAlives: false,
})
for i := 1; i <= 3; i++ {
resp, _ := client2.R().Get("https://httpbin.org/ip")
fmt.Printf("C-%d: %s\n", i, resp.String())
}
}
四种场景对比
| 场景 | net/http 实现 | resty 实现 |
|---|---|---|
| A | DisableKeepAlives: true + 每次新 Client | 每次新 resty.New() |
| B | 复用 Transport + 启 KeepAlive | 复用 resty 实例 |
| C-HTTP | 请求头 Proxy-Tunnel | SetHeader("Proxy-Tunnel", ...) |
| C-HTTPS | ProxyConnectHeader 设置头 | 底层 Transport 设置 |
错误排查
curl -x http://$PROXY_USERNAME:$PROXY_PASSWORD@$PROXY_HOST:$PROXY_PORT https://httpbin.org/ip
407 核对凭据,429 降低并发,504 重试。
需要企业代理方案?
我们可根据目标站点、并发规模与稳定性目标提供定制方案。