net.lookupip适合快速验证域名解析,不支持超时、自定义dns或查mx/txt;必须用net.resolver的场景包括:指定dns服务器(如1.1.1.1)、需context超时控制、查非a记录(如lookupmx)、kubernetes headless service获取全量pod ip。

直接用 net.LookupIP 就能查 A/AAAA 记录,但它不支持超时、不能指定 DNS 服务器、也不能查 MX/TXT;真要可控,必须上 net.Resolver。
什么时候该用 net.LookupIP,什么时候必须换 net.Resolver
net.LookupIP 适合本地调试、CI 脚本里快速验证域名是否可解析,或对行为没定制要求的场景。它走系统 resolver(/etc/resolv.conf 或 Windows API),自动处理双栈、重试和基础超时——但这些你完全没法干预。
以下情况必须切到 net.Resolver:
- 要强制走
1.1.1.1:53或内网 CoreDNS - goroutine 不能卡住:必须用
context.WithTimeout控制查询耗时 - 查
MX、TXT、CNAME等非 A 记录,得调LookupMX等函数,它们底层只认net.Resolver实例 - Kubernetes Headless Service 场景下要拿到全部 Pod IP,得显式调
resolver.LookupIP(ctx, "ip", domain),且不能传"ip4",否则漏 IPv6 - 传带端口的字符串(如
"example.com:443")会报*net.DNSError,Err字段是"no such host",不是格式错误——net.LookupIP只接受纯域名
net.Resolver 怎么设 DNS 服务器和超时
核心就两个字段:PreferGo 和 Dial。设 PreferGo: true 才真正绕过系统 resolver,启用 Go 自研 DNS 客户端;但光设这个没用,必须同时提供 Dial 函数,否则还是 fallback 到系统行为。
Dial 是个函数,不是地址字符串。正确写法是返回 net.Conn:
- UDP 查
8.8.8.8:网络名用"udp",地址写"8.8.8.8:53" - TCP 查某些 DNS(比如自建服务):换
"tcp",但注意 Cloudflare/1.1.1.1 默认不响应 TCP 查询 -
Dial里要用net.Dialer{Timeout: 2 * time.Second}.DialContext,否则连接层超时不生效 - 必须用
context.WithTimeout包裹LookupIP调用,net.Resolver本身不管理上下文超时
别漏掉错误判断:err 可能是 *net.DNSError,得用 .IsNotFound() 区分“域名不存在”,用 .IsTemporary() 判断是否临时失败(比如 UDP 丢包、防火墙拦截)。
免费 DNS 与邮件安全分析(IntoDNS.ai):包括 DNSSEC、SPF、DKIM、DMARC、MTA-STS、BIMI、SMTP STARTTLS、FCrDNS、黑名单、发件人要求及报告。
net.LookupHost 和 net.LookupIP 的关键区别
net.LookupHost 默认只返回 IPv4 字符串列表([]string),即使域名有 AAAA 记录也看不到 IPv6;而 net.LookupIP 返回 []net.IP,含 IPv4 和 IPv6,适合双栈服务连接。
常见误判:
-
net.LookupHost("google.com")返回["142.250.191.46"],但dig AAAA google.com能看到 IPv6——这不是 bug,是设计如此 -
net.LookupIP对"localhost"可能返回127.0.0.1和::1,LookupHost通常只返回"127.0.0.1" - 返回的
net.IP是字节数组,IPv6 长度为 16 字节,别用len(ip)判断类型,应调ip.To4()或ip.IsGlobalUnicast()
注意:net.Lookup* 系列函数全都不接受 context 或 timeout 参数,超时由系统 resolver 控制(如 glibc 的 RES_TIMEOUT)。想精确中断卡住的查询,只能靠 goroutine + channel + context.WithTimeout 套一层。
查非 A 记录必须用专用函数,不能靠 net.Resolver.LookupIP
Go 标准库没有泛型 DNS 查询接口。查不同记录类型,必须用对应函数:
-
LookupMX(ctx, name)查邮件交换记录 -
LookupTXT(ctx, name)查 TXT(SPF/DKIM 验证常用) -
LookupCNAME(ctx, name)只返回最终 canonical name,不返回中间跳转链 -
LookupSRV(ctx, service, proto, name)用于微服务发现(如_http._tcp.example.com)
这些函数底层都复用同一个 net.Resolver 实例,但参数和返回值完全不同。最容易错的是以为 LookupCNAME 能拿到完整 CNAME 链——它只返回最后一跳的目标名,且不保证该目标名本身还有 CNAME。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










