Java 使用SSL或TLSv1.2时,将忽略Apache HttpClient-keepalive

Java 使用SSL或TLSv1.2时,将忽略Apache HttpClient-keepalive,java,web-services,apache-httpclient-4.x,tls1.2,tcp-keepalive,Java,Web Services,Apache Httpclient 4.x,Tls1.2,Tcp Keepalive,我将ApacheHttpClient 4.5用于我的soap Web服务 目前,我遇到了一个问题,在使用TLSv1.2时,httpclient中的keep-alive被忽略。但是,如果使用HTTP,则“保持活动”正在工作 你们有什么想法吗 我的代码如下所示: 主类:HttpClientPool.java public class HttpClientPool { private static PoolingHttpClientConnectionManager manager = nu

我将ApacheHttpClient 4.5用于我的soap Web服务

目前,我遇到了一个问题,在使用TLSv1.2时,httpclient中的keep-alive被忽略。但是,如果使用HTTP,则“保持活动”正在工作

你们有什么想法吗

我的代码如下所示:

主类:HttpClientPool.java

public class HttpClientPool {

    private static PoolingHttpClientConnectionManager manager = null;
    private static CloseableHttpClient httpClient = null;
    private static final Logger logger = Logger.getLogger(HttpClientPool.class);

    public static synchronized CloseableHttpClient getHttpClient(){

        if(httpClient==null){

            //Some function to get SSLConnectionSocketFactory in Singleton
            SSLConnectionSocketFactory sslConnSocFac = getSSLConnectionSocketFactory();

            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("https", sslConnSocFac)
                    .build();

            HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connectionFactory = new ManagedHttpClientConnectionFactory(
                    DefaultHttpRequestWriterFactory.INSTANCE, DefaultHttpResponseParserFactory.INSTANCE);

            DnsResolver dnsResolver = SystemDefaultDnsResolver.INSTANCE;

            manager = new PoolingHttpClientConnectionManager(socketFactoryRegistry, connectionFactory, dnsResolver);

            SocketConfig deaultSocketConfig = SocketConfig.custom().setTcpNoDelay(true).build();
            manager.setDefaultSocketConfig(deaultSocketConfig);
            manager.setMaxTotal(300);
            manager.setDefaultMaxPerRoute(200);
            manager.setValidateAfterInactivity(50*1000);

            RequestConfig defaultRequestConfig = RequestConfig.custom()
                    .setConnectTimeout(20*1000)
                    .setSocketTimeout(50*1000)
                    .setConnectionRequestTimeout(20000)
                    .build();

            ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
                public long getKeepAliveDuration(HttpResponse httpResponse, org.apache.http.protocol.HttpContext context) {
                    return 1000 * 1000;
                }
            };

            httpClient = HttpClients.custom()
                    .setConnectionManager(manager)
                    .setConnectionManagerShared(false)
                    .evictIdleConnections(60l, TimeUnit.SECONDS)
                    .evictExpiredConnections()
                    .setConnectionTimeToLive(60, TimeUnit.SECONDS)
                    .setDefaultRequestConfig(defaultRequestConfig)
                    .setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE)
                    .setKeepAliveStrategy(myStrategy)
                    .setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))
                    .build();

            Runtime.getRuntime().addShutdownHook(new Thread(){
                @Override
                public void run(){
                    try {
                        httpClient1.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        return httpClient;
    }

    private static SSLConnectionSocketFactory getSSLConnectionSocketFactory() {
        //some working
        return sslConnectionSocketFactory;
    }

}

这里有两个选项:

  • 将用户令牌(在您的情况下应该是用户证书的CN)作为参数传递给
    #sendSOAPMessage

    public class webServiceClient{
    
        HttpClientPool httpClientPool;
    
        private static final Logger logger = Logger.getLogger(HttpClientPool.class);
    
        public sendSOAPMessage(String url, String soapAction, String userToken){
            HttpPost post = new HttpPost(url);
            HttpEntity entity = new ByteArrayEntity(xml.getBytes("UTF-8"));
    
            post.setEntity(entity);
            post.setHeader("Content-type", "application/soap+xml; charset=UTF-8");
            post.setHeader("SOAPAction", soapAction);
            post.setHeader("Connection", "Keep-Alive");
            post.setHeader("Keep-Alive", "header");
    
            HttpClientContext clientContext = HttpClientContext.create();
            clientContext.setUserToken(userToken);
            try (CloseableHttpResponse response = httpClientPool.getHttpClient().execute(post, clientContext)) {
                String result = EntityUtils.toString(response.getEntity());
                logger.info("Response: " + result);
    
                EntityUtils.consume(response.getEntity());
            }
        }
    }
    
  • 如果您确定应用程序不必支持多个用户标识,请禁用连接状态跟踪

    httpClient = HttpClients.custom()
        .disableConnectionState()
        .build();    
    

  • 您的应用程序是否使用基于证书的客户端身份验证?嗨,ok2c,我想是的。我将做以下工作:1。将密钥库和信任库放入KeyManager和TrustManager 2中。将KeyManager和TrustManager放入SSLContext 3。通过放置SSLContext和协议为TLSv1.2 4来创建org.apache.http.conn.ssl.SSLConnectionSocketFactory。通过放置SSLConnectionSocketFactory创建PoolightTPClientConnectionManager。SSLConnectionSocketFactory不会解决您眼前的问题,但至少解释了为什么HttpClient不会重复使用不共享相同会话/执行上下文的持久连接。感谢您的反馈。我无法在同一执行上下文下使用httpclient,因为它是从另一个类调用的。实现类A->webServiceClient->HttpClientPool。或者您有一个HttpClientPool的示例可以在相同的执行上下文下使用吗?您好,ok2c,我已经尝试了这两种方法,并且工作得很好。我将使用第一个选项,因为它可以处理多个用户身份。非常感谢您的反馈。这对我真的很有帮助。
    httpClient = HttpClients.custom()
        .disableConnectionState()
        .build();