Java Rest模板org.apache.http.NoHttpResponseException
我有两个Spring引导服务A和B,还有一个外部服务C。 这是请求路径: Web浏览器服务A服务B外部服务C 外部服务正在返回返回到前端的资源。对于A、B和C之间的通信,我使用Rest模板。 进入Web应用程序时一切正常,但只要我运行并行运行的BDD测试(9个线程),调用外部服务C时,服务B中就会出现NoHttpResponseExceptionJava Rest模板org.apache.http.NoHttpResponseException,java,spring,spring-boot,resttemplate,Java,Spring,Spring Boot,Resttemplate,我有两个Spring引导服务A和B,还有一个外部服务C。 这是请求路径: Web浏览器服务A服务B外部服务C 外部服务正在返回返回到前端的资源。对于A、B和C之间的通信,我使用Rest模板。 进入Web应用程序时一切正常,但只要我运行并行运行的BDD测试(9个线程),调用外部服务C时,服务B中就会出现NoHttpResponseException org.apache.http.NoHttpResponseException Service_C failed to respond at org.
org.apache.http.NoHttpResponseException Service_C failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
以下是我的Rest模板配置:
@Bean
public RestTemplate restTemplateExternal() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
HttpComponentsClientHttpRequestFactory requestFactory = getRequestFactoryWithDisabledSSLValidation();
RestTemplate restTemplate = new RestTemplate(requestFactory);
return restTemplate;
}
private HttpComponentsClientHttpRequestFactory getRequestFactoryWithDisabledSSLValidation() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.setSSLSocketFactory(csf)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return requestFactory;
}
我已经尝试调用connectionManager.setValidateAfterInactivity(0)代码>但它没有帮助
让我补充一下,从服务B到外部服务C的所有请求都是到同一个端点的。只有参数(x)正在更改:/resource?param={x}
老实说,我不能100%确定HttpClient是否将使用每个服务请求创建(RESTTemplatebean是单例的),或者每个服务只有一个实例
也许我需要在连接管理器中设置DefaultMaxPerRoute?如果是,那么如何区分正确的数字?如果能简单介绍一下在这种情况下如何正确配置RestTemplate,我将不胜感激。U可以尝试启用更多额外的日志记录,以便从服务器中搜索隐藏的异常。
服务器似乎断开了连接。这里的问题类似:
尝试使用clientBuilder.setRetryHandler(新的DefaultHttpRequestRetryHandler(3,true))代码>成功了。如果有人能更深入地解释这个问题,我仍将不胜感激。问题可能是因为响应包含标题connections=close
。因此,一个连接被关闭,但下一个请求尝试重用现有连接(已关闭)并获得错误
setRetryHandler
在第一次连接重用时总是失败,但在第二次重试时启动新连接,然后将成功
您可以通过以下行禁用以重用连接:
httpClient.setReuseStrategy(新的NoConnectionReuseStrategy())代码>如果您想在日志中看到重试,可以使用如下重试解决方案:
private void addRetryHandler( HttpClientBuilder httpClientBuilder ) {
logger.debug("adding retry handler to httpClient");
httpClientBuilder.setRetryHandler(( exception, executionCount, context ) -> {
if (executionCount > 3) {
logger.debug("Maximum http request tries reached for client http pool ");
return false;
}
if (exception instanceof org.apache.http.NoHttpResponseException) {
logger.debug("No response from server on {} call, got NoHttpResponseException", executionCount);
return true;
}
return false;
});
}
由连接管理器保持活动状态的最有可能的持久连接会过时。也就是说,当连接处于空闲状态时,目标服务器在其端关闭连接,而HttpClient无法对该事件做出反应,从而导致连接半关闭或“过时”。