unknownhostexception表示dns解析失败而非网络或服务故障,主因是域名非法、容器dns配置错误或系统resolv.conf异常;应优先验证域名格式与dns可达性,避免仅依赖try-catch。

Java抛出UnknownHostException说明DNS查不到域名
这个异常不是网络不通,也不是服务器宕机,而是JVM在调用系统DNS解析器时,压根没拿到IP地址——连发起TCP连接的机会都没有。常见于容器内DNS配置错误、/etc/resolv.conf被覆盖、或域名拼写有空格/下划线等非法字符。
- 检查是否真能解析:
nslookup example.com或dig example.com +short,别只ping IP - Java默认用系统DNS,不走/etc/hosts(除非启用了
sun.net.spi.nameservice.provider.1=dns,sun) - 如果用OpenJDK 17+,注意
jdk.net.hosts.file系统属性可强制指定hosts路径,但不会自动 fallback 到DNS
catch UnknownHostException不如提前验证域名格式和可达性
直接try-catch这个异常效果差:它不区分“域名不存在”和“DNS服务不可达”,且无法重试或降级。更务实的做法是把校验前移。
- 用
java.net.IDN.toASCII()标准化国际化域名(IDN),避免café.com这类带Unicode的域名失败 - 用
InetAddress.getByName(host).isAnyLocalAddress()快速排除localhost类特殊地址(某些环境会误解析为0.0.0.0) - 对关键服务,启动时就调用
InetAddress.getAllByName(host)并缓存结果,比每次请求都解析更稳
在Docker/K8s里UnknownHostException大概率是DNS配置问题
Java进程继承宿主或Pod的DNS设置,但glibc和musl行为不同,Alpine镜像尤其容易翻车。
- 确认容器内
/etc/resolv.conf有可用nameserver(不是127.0.0.11这种docker内部地址,除非你明确配了dockerd DNS) - 用
busybox:latest镜像执行nslookup对比,排除Java特有问题 - 加JVM参数
-Dsun.net.inetaddr.ttl=30降低DNS缓存时间,避免旧记录长期生效(默认是30秒,但失败缓存是10秒,不可改)
不要用InetAddress.getByName()做服务发现
它只返回一个IP(通常是第一个A记录),而现代服务注册中心需要全部健康实例。一旦DNS轮询或SRV记录返回多个地址,这个方法就丢信息。
立即学习“Java免费学习笔记(深入)”;
- 改用
InetAddress.getAllByName(host)拿全量IPv4/IPv6地址列表 - 若需SRV支持(如
_http._tcp.api.example.com),必须用第三方库如dnsjava,标准库不支持 - 注意
getByName()在超时前会阻塞线程,高并发场景务必设sun.net.inetaddr.ttl并配合超时逻辑
最麻烦的不是异常本身,是它常掩盖底层DNS基础设施问题——比如CoreDNS配置了forward但上游超时静默丢包,Java只会报UnknownHostException,连错误码都不给。










