Go语言通过代理发送HTTP请求时指定CDN服务器IP的规范实现问询
实现方案
Go标准库提供了两种更规范的实现,无需手动拼接IP到URL、手动修改req.Host,逻辑更清晰,也天然兼容HTTPS场景的证书校验、SNI等逻辑。
方案1:自定义DialContext固定连接IP(适合单请求指定IP场景)
直接重写http.Transport的DialContext逻辑,不管请求的域名是什么,TCP连接直接指向你指定的IP即可:
package main import ( "context" "fmt" "io" "net" "net/http" "net/url" ) func HttpReq( method, targetDomain, path, targetIP, proxyAddr string, ) ([]byte, error) { // 解析代理配置 proxy, err := url.Parse(proxyAddr) if err != nil { return nil, err } netTransport := &http.Transport{ Proxy: http.ProxyURL(proxy), // 自定义拨号逻辑,固定使用指定IP建立连接 DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { // addr 原本是 域名:端口 的格式,这里直接替换成 指定IP:端口 _, port, err := net.SplitHostPort(addr) if err != nil { return nil, err } return net.Dial(network, net.JoinHostPort(targetIP, port)) }, } client := &http.Client{Transport: netTransport} // 这里直接用正常的域名构造请求即可,不需要用IP拼接 req, err := http.NewRequest(method, fmt.Sprintf("http://%s%s", targetDomain, path), nil) if err != nil { return nil, err } resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() return io.ReadAll(resp.Body) } func main() { targetDomain := "neverssl.com" path := "/" // 直接指定要访问的CDN节点IP即可 targetIP := "18.65.145.96" proxyAddr := "socks5://127.0.0.1:3425" body, err := HttpReq(http.MethodGet, targetDomain, path, targetIP, proxyAddr) fmt.Println(err) fmt.Println(string(body)) }
方案2:自定义Resolver劫持DNS解析(适合批量请求场景)
如果你有大量同一域名的请求都要走指定IP,可以重写DNS解析逻辑,把目标域名的解析结果固定为你指定的IP,所有请求都不用单独修改逻辑:
// 只需要修改Transport的Dialer的Resolver即可 netTransport := &http.Transport{ Proxy: http.ProxyURL(proxy), DialContext: (&net.Dialer{ Resolver: &net.Resolver{ PreferGo: true, Dial: func(ctx context.Context, network, address string) (net.Conn, error) { // 这里可以做自定义DNS逻辑,比如固定返回你指定的IP return nil, nil }, }, }).DialContext, }
如果只需要固定单域名的解析结果,也可以直接在Resolver的LookupHost方法里做拦截,所有对目标域名的解析都会直接返回你预设的IP。
两种方案的优势
- 无需手动修改请求的
Host头,标准库会自动填充正确的域名 - HTTPS场景下也能自动完成SNI扩展、证书域名校验,不会出现证书不匹配的问题
- 业务逻辑和节点IP配置解耦,调整测试IP时不需要修改请求构造逻辑
内容的提问来源于stack exchange,提问作者aj3423
相关产品推荐
相关产品推荐

