golang 发起 http 请求,获取访问域名的 ip 地址(net, httptrace)

前言

今天碰到了个需求,我要知道程序对外访问的 http 请求域名的 ip 地址。

直接查看 golang 的 net/http 包,发现 Response 中并没有我想要的 ip 信息。

考虑到在 OSI 七层模型中,ip 是网络层协议,而 http 是应用层协议。去翻了下 net 包,发现了基础用法。

先提一下,域名访问服务器是会通过 dns 服务器去获取服务器的 ip(这块知识不了解的可以先去了解下),我们日常访问域名的过程:域名 -> dns 服务器 -> 需要访问的服务器的 ip 。 dns 服务器有可能回返回多个 ip,一般程序都会使用第一个进行数据交互。

go 中的使用

1. net 包

源码 net/lookup.go 中有相关的获取方式,测试代码如下:

go 复制代码
package main

import (
	"fmt"
	"log"
	"net"
)

func main() {
	useNetParse()
}

func useNetParse() {
	host := "www.baidu.com"
	ips, err := net.LookupIP(host)
	if err != nil {
		log.Fatal(err)
	}
	for _, v := range ips {
		fmt.Println("DNS 解析:", v.String())
	}

	ip, err := net.ResolveIPAddr("ip", host)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("服务器 IP 地址:", ip.String())
}

输出

复制代码
DNS 解析: 180.101.50.188      
DNS 解析: 180.101.50.242      
服务器 IP 地址: 180.101.50.188

2. httptrace

简单介绍下 httptrace,它是 go 1.17 后添加的新方法,用于在客户端请求的整个生命周期中收集细粒度信息的工具。

它提供了许多的钩子,如:

  • 连接创建
  • 连接复用
  • DNS 查询
  • 将请求写入网路
  • 读取响应

获取 DNS 查询使用的是 DNSDone 这个钩子,但是 DNS 解析后可能会解析出多个 IP 地址,而我需要的是访问服务器的 IP 地址,可以使用 GotConn 这个钩子,在连接成功创建后查看其访问的服务器的 IP 地址。

测试代码如下:

go 复制代码
package main

import (
	"fmt"
	"log"
	"net/http"
	"net/http/httptrace"
)

func main() {
	req, _ := http.NewRequest("GET", "https://www.baidu.com", nil)
	trace := &httptrace.ClientTrace{
		DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
			fmt.Printf("DNS Info: %+v\n", dnsInfo)
		},
		GotConn: func(connInfo httptrace.GotConnInfo) {
			fmt.Printf("Got Conn: %+v\n", connInfo.Conn.RemoteAddr().String())
		},
	}
	req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
	_, err := http.DefaultTransport.RoundTrip(req)
	if err != nil {
		log.Fatal(err)
	}
}

输出:

复制代码
DNS Info: {Addrs:[{IP:180.101.50.188 Zone:} {IP:180.101.50.242 Zone:}] Err:<nil> Coalesced:false}
Got Conn: 180.101.50.188:443

可以看到这里访问的实际服务器的 IP 地址是 DNS 解析出的第一个 IP 地址。

其他查看服务器 ip 的方法

1. 浏览器 F12 调试

可以通过浏览器调试进行查看

2. ping

shell 复制代码
ping www.baidu.com

输出

复制代码
正在 Ping www.a.shifen.com [180.101.50.188] 具有 32 字节的数据:
来自 180.101.50.188 的回复: 字节=32 时间=21ms TTL=50
来自 180.101.50.188 的回复: 字节=32 时间=8ms TTL=50
来自 180.101.50.188 的回复: 字节=32 时间=8ms TTL=50
来自 180.101.50.188 的回复: 字节=32 时间=7ms TTL=50

180.101.50.188 的 Ping 统计信息:
    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 7ms,最长 = 21ms,平均 = 11ms

3. nslookup

shell 复制代码
nslookup www.baidu.com

输出

复制代码
服务器:  public1.alidns.com
Address:  223.5.5.5

非权威应答:
名称:    www.a.shifen.com
Addresses:  240e:e9:6002:15a:0:ff:b05c:1278
          240e:e9:6002:15c:0:ff:b015:146f
          180.101.50.242
          180.101.50.188
Aliases:  www.baidu.com

总结

本篇介绍了在 go 中如何获取访问域名的 ip 地址,通过 go 官方 net 包可获取。

如果有记录 http 请求的域名 ip 这种需求,可以使用 go 1.17 后添加的 httptrace 包来插入钩子获取请求的 ip 地址。当然了,httptrace 的作用不止于此,它可以搜集 http 客户端请求整个生命周期中的信息,本篇未做详细介绍,感兴趣的可自行探索。

参考

相关推荐
紧跟先前的步伐4 分钟前
Go AI Agent 实战 17|模型适配层设计:让模型可替换
开发语言·人工智能·后端·ai·golang
l1t1 小时前
DeepSeek辅助编写连接sqlite的CLI
数据库·golang·sqlite
计算机就业还在扩大1 小时前
第2期-cmp.Ordered+类型推断+刻意未支持的特性
后端·面试·golang
奇牙coding3 小时前
doubao-seed-2.1-pro 报 HTTP 401 怎么办?Key 正确也要检查请求头和端点
网络·数据库·http·ai
砺星Leetx10 小时前
工业总线选型与对接实战:PROFINET、EtherCAT、EtherNet/IP、PROFIBUS、Modbus-TCP 与 CC-Link
网络·网络协议·tcp/ip·控制器·国产拧紧系统
科技小登13 小时前
网站和游戏怎么选高防?DDoS防护、高防IP与高防CDN接入方案解析与边界评估
tcp/ip·ddos
Lsetea16 小时前
curl访问HTTPS报47 Too many redirects:重定向循环与max-redirs排查
linux·http·https·ssl证书·curl
treesforest16 小时前
游戏账号安全风险分层方案:IP信号分层与人机复核实践
tcp/ip·安全·游戏·1024程序员节
念何架构之路17 小时前
Go reflect 包:结构体反射 —Field、Tag 与 VisibleFields
java·数据库·golang