net.lookupip 返回空或报错主因是输入含协议前缀、dns配置异常或系统限制;应传纯域名,用net.resolver自定义超时与prefergo,并优先选lookuphost或lookupnetip按需查a/aaaa记录。

net.LookupIP 返回空结果或报错:检查域名格式和网络环境
常见错误是传入带协议前缀的 URL(比如 https://example.com),net.LookupIP 只接受纯域名(如 example.com)或 IPv4/IPv6 地址字符串。传错会直接返回 "no such host" 错误。
- 确保输入是合法域名,不带
http://、www.不是必须但需注意是否实际注册了该子域 - 本地 DNS 配置可能影响结果:Mac/Linux 查
/etc/resolv.conf,Windows 看网络适配器的 DNS 设置 - 某些内网环境(如公司代理后)会拦截或重定向 DNS 请求,可临时换用公共 DNS 测试:
1.1.1.1或8.8.8.8 - Go 默认使用系统解析器,不走
/etc/hosts—— 除非你显式调用net.DefaultResolver并设置PreferGo: true
想查 A 记录还是 AAAA?用 LookupHost 更可控
net.LookupIP 返回的是混合 IPv4/IPv6 地址切片,顺序不保证,且无法指定只查某类记录。如果你明确只需要 IPv4(比如对接老系统),或者想区分响应类型,net.LookupHost 是更稳的选择——它只返回 []string 域名解析结果,底层由 Go 自己的解析器控制,行为更一致。
-
net.LookupIP("example.com")可能返回[2606:2800:220:1:248:1893:25c8:1946 93.184.216.34],顺序因系统而异 -
net.LookupHost("example.com")总是返回字符串切片,内容取决于系统配置,但至少不会混 IP 版本 - 若真要分离 A/AAAA,建议用
net.Resolver+LookupNetIP,并传入"ip4"或"ip6"作为网络参数
超时控制不能靠 defer 或 context.Background()
net.LookupIP 本身不接受 context.Context,默认使用系统级 DNS 超时(通常几秒到十几秒),容易卡住 goroutine。别指望用 defer 或包一层 context.Background() 解决。
- 正确做法是创建自定义
*net.Resolver,设置Timeout和PreferGo: true - 示例:
r := &net.Resolver{ PreferGo: true, Dial: func(ctx context.Context, network, addr string) (net.Conn, error) { d := net.Dialer{Timeout: 3 * time.Second} return d.DialContext(ctx, network, addr) }, } ips, err := r.LookupIP(context.Background(), "ip4", "example.com") - 注意:
PreferGo: false(默认)会调用 libc 的getaddrinfo,此时Dial函数不生效,超时由系统决定
并发查多个域名时,别直接起一堆 goroutine 调 LookupIP
看似简单粗暴的并发(比如 for-range + go func())在高频率下容易触发系统 DNS 并发限制,尤其在 macOS 上表现明显:大量 "operation was canceled" 或延迟飙升。
立即学习“go语言免费学习笔记(深入)”;
- 用带限流的
net.Resolver实例比裸调net.LookupIP更可靠 - 避免复用同一个
net.Resolver实例做高频短连接;它的内部 DNS 连接池对 UDP 查询支持有限 - 如果批量查询固定域名集,考虑用
hostess类工具预查缓存,或自己加一层内存 map + TTL 控制 - UDP 查询本身无连接状态,但系统级 resolver(如 systemd-resolved)可能对单 IP 源端口频次做限制
事情说清了就结束。DNS 查询看着简单,真正压测或跨平台部署时,系统差异、超时策略、IPv6 fallback 行为这些点最容易漏掉。











