HttpClient 使用连接池 Pool 构建链接(兼容HTTPS)

Posted OkidoGreen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HttpClient 使用连接池 Pool 构建链接(兼容HTTPS)相关的知识,希望对你有一定的参考价值。

HttpClient 每次使用后到底需不需要 close,特别是在使用连接池的情况下

What is the difference between CloseableHttpClient and HttpClient in Apache HttpClient API?

https://stackoverflow.com/questions/21574478/what-is-the-difference-between-closeablehttpclient-and-httpclient-in-apache-http

The other answers don't seem to address why close() is really necessary? * 2

Doubt on the answer "HttpClient resource deallocation".

It is mentioned in old 3.x httpcomponents doc, which is long back and has a lot difference from 4.x HC. Besides the explanation is so brief that doesn't say what this underlying resource is.

I did some research on 4.5.2 release source code, found the implementations of CloseableHttpClient:close() basically only closes its connection manager.

(FYI) That's why when you use a shared PoolingClientConnectionManager and call client close(), exception java.lang.IllegalStateException: Connection pool shut down will occur. To avoid, setConnectionManagerShared works.

I prefer not do CloseableHttpClient:close() after every single request

I used to create a new http client instance when doing request and finally close it. In this case, it'd better not to call close(). Since, if connection manager doesn't have "shared" flag, it'll be shutdown, which is too expensive for a single request.



import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by Administrator on 2018/05/09.
 */
public class HttpClientUtil 
    private static HttpClientContext context = HttpClientContext.create();
    private static RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(200).setSocketTimeout(500)
            .setConnectionRequestTimeout(200).setCookieSpec(CookieSpecs.STANDARD_STRICT).
                    setExpectContinueEnabled(true).
                    setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST)).
                    setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)).build();

    //https
    private static SSLConnectionSocketFactory socketFactory;
    private static TrustManager manager = new X509TrustManager() 

        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException 

        

        @Override
        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException 

        

        @Override
        public X509Certificate[] getAcceptedIssuers() 
            return null;
        
    ;

    private static void enableSSL() 
        try 
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]manager, null);
            socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
         catch (NoSuchAlgorithmException e) 
            e.printStackTrace();
         catch (KeyManagementException e) 
            e.printStackTrace();
        
    

    private static HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() 
        @Override
        public boolean retryRequest(IOException exception,
                                    int executionCount, HttpContext context) 
            return false;
        ;
    static 
        enableSSL();
    
    private static Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", PlainConnectionSocketFactory.INSTANCE).register("https", socketFactory).build();

    private static PoolingHttpClientConnectionManager pccm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
    static 
        pccm.setMaxTotal(100); // 连接池最大并发连接数
        pccm.setDefaultMaxPerRoute(20); // 单路由最大并发数
    
    private static HttpClientBuilder clientBuilder = HttpClients.custom().setConnectionManager(pccm).
            setConnectionManagerShared(true).setRetryHandler(myRetryHandler)
                .setDefaultRequestConfig(requestConfig);
    /**
     * https get
     * @param url
     * @param data
     * @return
     * @throws IOException
     */
    public static CloseableHttpResponse doGet(String url, String data)
        CloseableHttpClient httpClient = clientBuilder.build();
        HttpGet httpGet = new HttpGet(url);
        CloseableHttpResponse response = null;
        try 
            response = httpClient.execute(httpGet, context);
        catch (Exception e)
            e.printStackTrace();
        
        return response;
    


    /**
     * https/http post
     * @param url
     * @param values
     * @return
     * @throws IOException
     */
    public static CloseableHttpResponse doPost(String url, List<NameValuePair> values) 
        CloseableHttpClient httpClient = clientBuilder.build();
        HttpPost httpPost = new HttpPost(url);
        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(values, Consts.UTF_8);
        httpPost.setEntity(entity);
        CloseableHttpResponse response = null;
        try 
            response = httpClient.execute(httpPost, context);
        catch (Exception e)
        return response;
    


    public static CloseableHttpResponse doJsonPost(String url,String json)
        CloseableHttpClient httpClient = clientBuilder.build();

        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse httpResponse;
        httpPost.addHeader(HTTP.CONTENT_TYPE, "application/json");
        httpPost.addHeader("charset", "utf-8");
        CloseableHttpResponse response = null;
        try 
            response = httpClient.execute(httpPost, context);
        catch (Exception e)
        return response;
    


    /**
     * 直接把Response内的Entity内容转换成String
     *
     * @param httpResponse
     * @return
     */
    public static String toString(CloseableHttpResponse httpResponse) 
        if(httpResponse == null) return null;
        // 获取响应消息实体
        String result = null;
        try 
            HttpEntity entity = httpResponse.getEntity();
            if (entity != null) 
                result = EntityUtils.toString(entity,"UTF-8");
            
        catch (Exception e)finally 
            try 
                httpResponse.close();
             catch (IOException e) 
                e.printStackTrace();
            
        
        return result;
    

    public static void main(String[] args)
        CloseableHttpResponse response = HttpClientUtil.doGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wxb2ebe42765aad029&secret=720661590f720b1f501ab3f390f80d52","");
        System.out.println(HttpClientUtil.toString(response));

        response = HttpClientUtil.doPost("http://www.baidu.com/cgi-bin/token?grant_type=client_credential&appid=wxb2ebe42765aad029&secret=720661590f720b1f501ab3f390f80d52",
                new ArrayList<NameValuePair>());
        System.out.println(HttpClientUtil.toString(response));
    


以上是关于HttpClient 使用连接池 Pool 构建链接(兼容HTTPS)的主要内容,如果未能解决你的问题,请参考以下文章

HttpClient 4.3连接池参数配置及源码解读

优雅代码08-构建自己的连接池

commons-pool2

使用 HttpClient 的 HTTP 连接池

HttpClient连接池的一些思考

使用commons.pool2实现mysql连接池