接入指南
Go 代理设置:net/http 账号密码认证
Go 标准库本身就能连接带认证的代理,不需要额外的包。代理以函数的形式挂在 Transport 上,登录信息放在 URL 的 userinfo 部分,https 网站通过 CONNECT 隧道访问。示例在 Go 1.27 上运行过。
开始之前
- PATH 中可用的 Go 工具链。代码只用到 net/http 和 net/url 中存在已久的接口,当前任何版本都可以。
- 一个用来放小模块的文件夹,第 1 步会创建它。
- 从服务页面复制的 HOST、PORT、USERNAME 和 PASSWORD。
你的连接信息
登录控制台,打开你购买的服务。服务页面上会显示该服务的主机、端口、用户名和密码。ProxyPanda 没有一个统一的固定地址,所以每次都请从那里复制。指南中的代码使用下面这些占位符,请逐一替换成你自己的值。
- HOST
- 该服务的代理地址,按服务页面上显示的原样填写。
- PORT
- 要连接的端口。请和主机一起复制,因为不同服务的端口可能不同。
- USERNAME
- 你的代理登录名。它与你登录控制台所用的邮箱是分开的。
- PASSWORD
- 请完整复制。住宅代理在控制台中选择的选项会附加在密码末尾,凭记忆手动输入的密码会丢失这些选项。
把你用来连接的 IP 地址加入服务的白名单,就可以不用用户名和密码。这时代码里只需要 HOST 和 PORT。
示例都使用 HTTP,它可以通过加密隧道访问 https 网站。SOCKS5 同样可用:住宅代理的端口两种都接受,ISP 和数据中心代理在控制台里切换协议。
步骤
创建模块
go version 会确认运行代码的是哪个工具链。下面每个示例都是这个文件夹里完整的 main.go,每次替换文件内容后用 go run . 运行。
terminal go version mkdir proxycheck && cd proxycheck go mod init proxycheck让 Transport 指向代理
http.ProxyURL 把一个固定的 URL 包装成 Transport 每次请求都会调用的函数。url.UserPassword 保存登录信息,并在写出 URL 时自动做百分号编码,所以密码里有 @、: 或 / 也不用手动转义。Client.Timeout 限制整次请求的时间,连向代理的 CONNECT 也包括在内。
main.go package main import ( "fmt" "io" "net/http" "net/url" "time" ) func main() { proxyURL := &url.URL{ Scheme: "http", User: url.UserPassword("USERNAME", "PASSWORD"), Host: "HOST:PORT", } client := &http.Client{ Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)}, Timeout: 30 * time.Second, } resp, err := client.Get("https://api.ipify.org?format=json") if err != nil { fmt.Println("request failed:", err) return } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(resp.Status, string(body)) }运行并检查出口
go run . 会打印 200 OK,后面是 api.ipify.org 返回的 JSON。ip 字段就是网站看到的地址,应当属于代理。
设置 Transport 超时,每个请求用新连接
Dialer 的超时限制连上代理的时间,TLSHandshakeTimeout 限制在隧道内与网站握手的时间,ResponseHeaderTimeout 限制等待第一个响应字节的时间。DisableKeepAlives 让每条连接只用一次就关闭:测试中,三次请求在开启它时建立了三条 CONNECT 隧道,关闭时只有一条。
main.go package main import ( "fmt" "io" "net" "net/http" "net/url" "time" ) func main() { proxyURL := &url.URL{ Scheme: "http", User: url.UserPassword("USERNAME", "PASSWORD"), Host: "HOST:PORT", } transport := &http.Transport{ Proxy: http.ProxyURL(proxyURL), DialContext: (&net.Dialer{Timeout: 10 * time.Second}).DialContext, TLSHandshakeTimeout: 10 * time.Second, ResponseHeaderTimeout: 30 * time.Second, DisableKeepAlives: true, } client := &http.Client{Transport: transport, Timeout: 60 * time.Second} for i := 0; i < 3; i++ { resp, err := client.Get("https://api.ipify.org") if err != nil { fmt.Println(i, "error:", err) continue } body, _ := io.ReadAll(resp.Body) resp.Body.Close() fmt.Println(i, string(body)) } }改为从 HTTPS_PROXY 读取代理
http.ProxyFromEnvironment 对 https 网址读取 HTTPS_PROXY,对 http 网址读取 HTTP_PROXY,并跳过 NO_PROXY 中列出的主机。http.DefaultTransport 已经在用它,但你自己创建的 Transport 不会:没有 Proxy 字段时,即使导出了变量,请求也会直接发出。
main.go package main import ( "fmt" "io" "net/http" "time" ) func main() { client := &http.Client{ Transport: &http.Transport{Proxy: http.ProxyFromEnvironment}, Timeout: 30 * time.Second, } resp, err := client.Get("https://api.ipify.org") if err != nil { fmt.Println("request failed:", err) return } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body)) }导出变量并运行
登录信息留在变量里,Go 代码中不出现任何凭据。这里的 URL 是纯文本,密码中的 @、: 或 / 需要你自己做百分号编码。如果这个 shell 还要给别的工具用,结束后取消这个变量。
terminal export HTTPS_PROXY="http://USERNAME:PASSWORD@HOST:PORT" go run .
轮换 IP 与粘性 IP
开启 keep-alive 时,Transport 会保持隧道,之后发往同一网站的请求都从这条隧道走,复用的隧道出口地址不变。住宅代理选“随机 IP”、又希望每个请求都能换地址时,请设置 DisableKeepAlives。
使用“粘性 IP”或 ISP、数据中心 IP 时,保持 keep-alive 开启即可。地址本来就应该不变,省去每次重新握手还能节省时间。
一个 http.Client 可以被多个 goroutine 共用。想把任务分到多个静态 IP 上,就为每个 IP 建一个 Transport,按请求选择。
常见错误与解决办法
Get "https://api.ipify.org…": Proxy Authentication Required
代理拒绝了登录。重新复制 USERNAME 和 PASSWORD。如果你用 url.Parse 从字符串构造代理 URL,要先对密码中的特殊字符做百分号编码,或者改用 url.UserPassword。
proxyconnect tcp: dial tcp …: connect: connection refused
HOST:PORT 上没有代理在监听。与服务页面核对两者,并确认服务仍然有效。
context deadline exceeded (Client.Timeout exceeded while awaiting headers)
在 Client.Timeout 用完之前没有收到响应。住宅出口是家庭网络,有些较慢,可以给这类请求更多时间,并只重试这一个网址。
程序打印的是你自己的地址
Transport 没有设置 Proxy 字段,或者 HTTPS_PROXY 是在另一个终端里导出的。自己创建的 Transport 在 Proxy 设为 http.ProxyFromEnvironment 之前,不会读取环境变量。
其他接入指南
有不明白的词? 术语表用大白话解释。
卡在某一步了?
把命令和报错贴到 Discord,记得先删掉密码。那里的人大多遇到过这些错误。