Java在Docker容器间调用HttpURLConnection报Connection refused如何解决?
问题排查与解决方案
这个现象的核心是容器网络层面连通性正常,但Java进程内部请求失败,按优先级排查以下原因即可:
常见原因1:Java进程读取了代理配置
大部分容器环境会默认设置http_proxy/https_proxy全局环境变量,JDK默认会自动读取这些环境变量作为全局HTTP代理。容器内部的服务域名(比如另一个容器的名称)不会走代理规则,会被直接转发到代理服务器,自然无法连通。
- 排查方式:在调用请求的代码前增加日志打印,输出以下系统属性:
System.out.println("http.proxyHost: " + System.getProperty("http.proxyHost")); System.out.println("http.proxyPort: " + System.getProperty("http.proxyPort")); System.out.println("Request URL: " + myUrl);
确认请求的URL和你wget使用的完全一致,同时没有配置多余的代理。
- 解决方案:如果确实存在代理配置,可以在Java启动参数中增加配置,排除容器内部域名的代理:
-Dhttp.nonProxyHosts="第二个容器名|localhost|127.0.0.1"
常见原因2:请求调用时机早于第二个服务就绪
从报错栈可以看出,请求是在Spring Bean初始化阶段触发的,属于第一个服务的启动流程。docker-compose的depends_on配置只能保证容器的启动顺序,无法保证第二个容器内部的Spring Boot应用完全启动完成、端口进入监听状态。你手动进入容器执行wget的时候,两个服务都已经完成启动,所以能正常访问,但启动阶段的调用就会失败。
- 解决方案:
- 给第二个容器配置健康检查,第一个容器等待第二个容器健康检查通过后再启动;
- 在请求代码中增加3-5次重试逻辑,每次间隔1-2秒,兼容服务启动的时间差;
- 调整代码逻辑,不要在Bean初始化阶段发起跨服务调用,改成第一次使用时懒加载调用。
常见原因3:JVM网络协议优先级问题
部分JDK版本默认优先使用IPv6协议栈,而Docker容器内部网络默认是IPv4,会导致域名解析异常。
- 解决方案:在第一个服务的Java启动参数中增加以下配置:
-Djava.net.preferIPv4Stack=true
其他排查方向
如果以上方案都无效,可以替换HTTP客户端验证:JDK自带的HttpURLConnection本身存在很多历史问题,换成Spring自带的RestTemplate或者OkHttp客户端发送请求,排除原生客户端的兼容性问题。
内容的提问来源于stack exchange,提问作者George Hernando
相关产品推荐
相关产品推荐

