Apache HttpClient5出现NoHttpResponseException:主机无响应问题求助
RestTemplate + Apache HttpClient5 出现 NoHttpResponseException 分析与解决
异常信息
Caused by: org.apache.hc.core5.http.NoHttpResponseException: <host> failed to respond at org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:301) at org.apache.hc.core5.http.impl.io.HttpRequestExecutor.execute(HttpRequestExecutor.java:175) at org.apache.hc.core5.http.impl.io.HttpRequestExecutor.execute(HttpRequestExecutor.java:218) at org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager$InternalConnectionEndpoint.execute(PoolingHttpClientConnectionManager.java:712) at org.apache.hc.client5.http.impl.classic.InternalExecRuntime.execute(InternalExecRuntime.java:216) at org.apache.hc.client5.http.impl.classic.MainClientExec.execute(MainClientExec.java:116) at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51) at org.apache.hc.client5.http.impl.classic.ConnectExec.execute(ConnectExec.java:188) at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51) at org.apache.hc.client5.http.impl.classic.ProtocolExec.execute(ProtocolExec.java:192) at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51) at org.apache.hc.client5.http.impl.classic.HttpRequestRetryExec.execute(HttpRequestRetryExec.java:96) at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51) at org.apache.hc.client5.http.impl.classic.ContentCompressionExec.execute(ContentCompressionExec.java:152) at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51) at org.apache.hc.client5.http.impl.classic.RedirectExec.execute(RedirectExec.java:115) at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51) at org.apache.hc.client5.http.impl.classic.InternalHttpClient.doExecute(InternalHttpClient.java:170) at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:106) at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:55) at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:93) at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:864)
问题原因
- 连接池复用无效连接:HttpClient连接池会复用TCP连接,若目标服务器主动断开空闲连接(比如超时回收),但客户端连接池未及时清理,复用该连接发送请求时就会报错。
- 服务器端过载或超时:目标服务压力过大,无法及时处理请求,直接关闭连接。
- 网络中间设备断开连接:防火墙、负载均衡器等设备在连接空闲一段时间后主动断开,客户端未感知。
- 服务器端异常:服务崩溃、重启,导致正在处理的请求被中断。
解决方案
1. 配置连接池的无效连接校验与回收
通过PoolingHttpClientConnectionManager设置空闲连接校验,每次使用连接前自动校验是否有效,同时配置连接存活时间:
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); // 设置最大总连接数和单路由最大连接数 connectionManager.setMaxTotal(200); connectionManager.setDefaultMaxPerRoute(20); // 每次使用连接前,校验空闲超过5秒的连接是否有效 connectionManager.setValidateAfterInactivity(TimeValue.ofSeconds(5));
2. 开启针对该异常的请求重试
配置HttpClient5的重试策略,对NoHttpResponseException这类可重试异常进行自动重试:
HttpRequestRetryStrategy retryStrategy = new DefaultHttpRequestRetryStrategy( 3, // 最大重试次数 TimeValue.ofSeconds(1), // 重试间隔时间 Collections.singleton(NoHttpResponseException.class) // 指定需要重试的异常 );
3. 设置合理的超时时间
配置连接超时、读取超时,避免长时间等待无响应的连接:
RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(TimeValue.ofSeconds(10)) // 连接超时10秒 .setResponseTimeout(TimeValue.ofSeconds(15)) // 读取响应超时15秒 .build();
4. 完整的RestTemplate配置示例
将以上配置整合到RestTemplate的Bean中:
@Bean public RestTemplate restTemplate() { PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); connectionManager.setMaxTotal(200); connectionManager.setDefaultMaxPerRoute(20); connectionManager.setValidateAfterInactivity(TimeValue.ofSeconds(5)); HttpRequestRetryStrategy retryStrategy = new DefaultHttpRequestRetryStrategy( 3, TimeValue.ofSeconds(1), Collections.singleton(NoHttpResponseException.class) ); RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(TimeValue.ofSeconds(10)) .setResponseTimeout(TimeValue.ofSeconds(15)) .build(); CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(connectionManager) .setRetryStrategy(retryStrategy) .setDefaultRequestConfig(requestConfig) .build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); return new RestTemplate(requestFactory); }
5. 服务器端排查
- 检查目标服务的日志,确认是否存在过载、崩溃或连接回收策略配置问题。
- 调整服务器端的连接超时设置,避免主动断开正常连接。
内容的提问来源于stack exchange,提问作者Raviteja
相关产品推荐
相关产品推荐

