休息模板org.apache.http.NoHttpResponseException

时间:2018-07-17 11:02:31

标签: java spring spring-boot resttemplate

我有两个Spring Boot服务A和B。还有一个外部服务C。 这就是请求路径:

Web浏览器<->服务A <->服务B <->外部服务C

外部服务返回的资源可以返回到前端。为了在A,B和C之间进行通信,我使用了Rest Template。 进入Web应用程序时一切正常,但是当我运行并行运行的BDD测试(9个线程)时,调用外部服务C时,服务B中就会收到NoHttpResponseException。

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 Template配置:

    @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(RestTemplate bean是Singleton)还是每个服务仅一个实例?

也许我需要在连接管理器中设置“ setDefaultMaxPerRoute”?如果是,那么我该如何区分正确的数字?我非常感谢在这种情况下如何正确配置RestTemplate的简短描述。

4 个答案:

答案 0 :(得分:1)

类似的问题在这里:get NoHttpResponseException for load testing

尝试过clientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true));,成功了。如果有人可以更深入地解释问题,我仍然很感激。

答案 1 :(得分:1)

问题可能是因为响应包含标头connections=close。因此,连接已关闭,但是下一个请求尝试重用现有的连接(已关闭)并获取错误。

setRetryHandler总是在第一次重用连接时失败,但是在第二次重试时开始新的连接,然后将成功。

您可以通过以下行拒绝重用连接: httpClient.setReuseStrategy(new NoConnectionReuseStrategy());

答案 2 :(得分:0)

U可以尝试启用更多其他日志记录来从服务器搜索隐藏的除外。 看来服务器断开了连接。

答案 3 :(得分:0)

如果要在日志中查看重试,可以使用如下重试解决方案:

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;
    });
}