CloseableHttpClient 执行调用导致 NoSuchElementException

问题描述 投票:0回答:1

团队您好:我有一个关于在 Spring Boot 3 应用程序中使用 Apache HttpClient 5 CloseableHttpClient 的问题。我正在执行以下代码:

        try
        {
            final HttpGet httpGet = new HttpGet("http://httpbin.org/get");
            httpGet.addHeader("content-type", "application/json");
            HttpClientResponseHandler<String> responseHandler = new HttpClientResponseHandler<String>()
            {
                @Override
                public String handleResponse(ClassicHttpResponse _httpResponse) throws HttpException, IOException 
                {
                    int status = _httpResponse.getCode();
                    if (status >= 200 && status < 300)
                    {
                        HttpEntity entity = _httpResponse.getEntity();
                        String stringEntity = EntityUtils.toString(entity);
                        return entity != null ? stringEntity : null;
                    }
                    else
                    {
                        throw new ClientProtocolException("Unexpected response status: " + status);
                    }
                }
            };
            responseBody = closeableHttpClient.execute(httpGet, responseHandler);
            log.info("Response Body: " + responseBody);
        }
        catch (NoSuchElementException _e)
        {
            log.error("NoSuchElementException: "+ _e.getMessage());
            _e.printStackTrace();
        }
        catch (ClientProtocolException _e)
        {
            log.error("ClientProtocolException: "+ _e.getMessage());
        }
        catch (IOException _e)
        {
            log.error("IOException: "+ _e.getMessage());
        }
        catch (Exception _e)
        {
            log.error("Exception: "+ _e.getMessage());
        }

但是当我执行这段代码时,出现以下异常:

NoSuchElementException:没有更多可用的标题元素 java.util.NoSuchElementException:没有更多可用的标头元素

要获取 CloseableHttpClient,我有以下配置:

@Slf4j
@Configuration
@EnableScheduling
public class HttpConfig
    @Bean
    @ConditionalOnMissingBean
    public CloseableHttpClient httpClient(HttpClientConnectionManager connectionManager)
    {
        RequestConfig requestConfig = RequestConfig.custom()
            .setConnectionRequestTimeout(Timeout.ofMilliseconds(15000))
            .setResponseTimeout(Timeout.ofMilliseconds(15000))
            .build();

        return HttpClients.custom()
            .setConnectionManager(connectionManager)
            .setKeepAliveStrategy(getConnectionKeepAliveStrategy())
            .setDefaultRequestConfig(requestConfig)
            .build();
    }

    @Bean(destroyMethod = "")
    @ConditionalOnMissingBean
    public HttpClientConnectionManager httpClientConnectionManager()
    {
        HttpHost host1 = new HttpHost("httpbin.org/get", 80);
        final PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
                .setConnectionFactory(getHttpConnectionFactory())
                .setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
                .setConnPoolPolicy(PoolReusePolicy.LIFO)
                .build();

        connectionManager.setMaxTotal(100);
        connectionManager.setDefaultMaxPerRoute(20);
        connectionManager.setMaxPerRoute(new HttpRoute(host1), 10);

        return connectionManager;
    }
    
    public ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy()
    {
        final ConnectionKeepAliveStrategy connectionKeepAliveStrategy = new ConnectionKeepAliveStrategy()
        {
            @Override
            public TimeValue getKeepAliveDuration(HttpResponse response, HttpContext context)
            {
                Args.notNull(response, "HTTP response");
                final Iterator<HeaderElement> iterator = MessageSupport.iterate(response, HeaderElements.KEEP_ALIVE);
                final HeaderElement headerElement = iterator.next();
                final String param = headerElement.getName();
                final String value = headerElement.getValue();
                if (value != null && param.equalsIgnoreCase("timeout"))
                {
                    try
                    {
                        return TimeValue.ofSeconds(Long.parseLong(value));
                    }
                    catch (final NumberFormatException e)
                    {
                        log.error("Connection Keep-Alive Strategy: Number Format Exception: Safely Ignore: " + e.getMessage());
                    }
                }
                return TimeValue.ofSeconds(5);
            }

        };
        return connectionKeepAliveStrategy; 
    }

    @Bean
    public Runnable getIdleConnectionMonitor(final PoolingHttpClientConnectionManager connectionManager)
    {
        return new Runnable()
        {
            @Override
            @Scheduled(fixedDelay = 15000)
            public void run()
            {
                try
                {
                    if (connectionManager != null)
                    {
                        connectionManager.closeExpired();
                        connectionManager.closeIdle(Timeout.ofSeconds(60000));
                    }
                }
                catch (Exception e)
                {
                    log.error("IdleConnectionMonitor - Exception occurred: Message = {}, Exception = {}", e.getMessage(), e);
                }
            }
        };
    }

我不知道这里出了什么问题。任何帮助将不胜感激。

java nosuchelementexception apache-httpclient-5.x
1个回答
0
投票

错误消息来自上面代码中此行

final HeaderElement headerElement = iterator.next();
处的 ConnectionKeepAliveStrategy 配置。

在 Spring 6.X 和 Spring Boot 3 中,org.apache.httpclient 更新为 org.apache.httpcomponents.client5:httpclient5,并且 httpclient5 生成的响应没有 HeaderElement,但标头是响应的一部分目的。因此,将实现更改为此将起作用。我已经在 Spring Boot 3.2.5 中的 ConnectiveKeepAliveStrategy 下面对此进行了测试

return new ConnectionKeepAliveStrategy() {
        @Override
        public TimeValue getKeepAliveDuration(HttpResponse httpResponse, HttpContext httpContext) {
            if(httpResponse.containsHeader(HeaderElements.KEEP_ALIVE)) {
                String keepAliveHeader = httpResponse.getFirstHeader(HeaderElements.KEEP_ALIVE).getValue();
                String timeoutValue = keepAliveHeader.replaceAll("[^0-9]", "");
                if(!timeoutValue.isEmpty()) {
                    return TimeValue.ofMilliseconds(Long.parseLong(timeoutValue) * 1000);
                }
            }
            return TimeValue.ofSeconds(3000);
        }
    };

希望这有帮助!

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.