HTTP连接池实例

HTTP连接池实例

关键字:PoolingHttpClientConnectionManager,HttpPost


我为何用写连接池?

  • 最近老板要我做一个支付平台统一接口
  • 支付平台接口逻辑基本都是对支付宝,微信,唯宝等其他服务的网络请求

我为何要用PoolingHttpClientConnectionManager?

  • 在找寻连接池的相关博客资料,引用(4.0)版本的HttpConnectionManager时发现已经Deprecated
  • 然后去到Apache官网查询下个版本(4.1)的ThreadSafeClientConnManager,很遗憾也过时了
  • 最后找到了(4.2)PoolingHttpClientConnectionManager是ok的
  • 既然是新的项目就想用最新的东西,更何况最新版本的HttpClent都已经4.5.*了(我有强迫症)

查询相关资料发现对应博文相对较少,而且并不是完全满足自身需求,以下推荐自身查阅的相关资料

  1. http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.html
    2.http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html (英文版)
    3.http://www.yeetrack.com/?p=782 (惊现中文版)
    4.https://my.oschina.net/ramboo/blog/519871/
这里贴下代码:
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
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.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.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpConnectionManager {

    private PoolingHttpClientConnectionManager connectionManager;
    private ConnectionSocketFactory plainsf ;
    private LayeredConnectionSocketFactory sslsf;
    private Registry registry ;
    private HttpRequestRetryHandler httpRequestRetryHandler;
    private CloseableHttpClient httpClient;

    private static HttpConnectionManager httpConnectionManager = new HttpConnectionManager();

    private static final Logger logger = LoggerFactory.getLogger(HttpConnectionManager.class);

    private HttpConnectionManager(){
        /**
         * LayeredConnectionSocketFactory是ConnectionSocketFactory的拓展接口。
         * 分层socket工厂类可以在明文socket的基础上创建socket连接。分层socket主要用于在代理服务器之间创建安全socket。
         * HttpClient使用SSLSocketFactory这个类实现安全socket,SSLSocketFactory实现了SSL/TLS分层
         * 自定义的socket工厂类可以和指定的协议(Http、Https)联系起来,用来创建自定义的连接管理器。
         */
        plainsf = PlainConnectionSocketFactory.getSocketFactory();
        sslsf = SSLConnectionSocketFactory.getSocketFactory();
        registry = RegistryBuilder.create()
                .register("http", plainsf)
                .register("https", sslsf)
                .build();
        connectionManager = new PoolingHttpClientConnectionManager(registry);
        // 将最大连接数增加到400
        connectionManager.setMaxTotal(400);
        // 将每个路由基础的连接增加到50
        connectionManager.setDefaultMaxPerRoute(50);
        //请求重试处理
        httpRequestRetryHandler = new HttpRequestRetryHandler() {

            @Override
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                 if (executionCount >= 1) {// 如果已经重试了1次,就放弃                    
                        return false;
                    }
                    if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接,那么就重试                    
                        return true;
                    }
                    if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常                    
                        return false;
                    }                
                    if (exception instanceof InterruptedIOException) {// 超时                    
                        return false;
                    }
                    if (exception instanceof UnknownHostException) {// 目标服务器不可达                    
                        return false;
                    }
                    if (exception instanceof ConnectTimeoutException) {// 连接被拒绝                    
                        return false;
                    }
                    if (exception instanceof SSLException) {// ssl握手异常                    
                        return false;
                    }

                    HttpClientContext clientContext = HttpClientContext.adapt(context);
                    HttpRequest request = clientContext.getRequest();
                    // 如果请求是幂等的,就再次尝试
                    if (!(request instanceof HttpEntityEnclosingRequest)) {                    
                        return true;
                    }
                    return false;
            }
        };
        httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setRetryHandler(httpRequestRetryHandler)
                .build();
    }

    public static HttpConnectionManager getInstance() {
        return httpConnectionManager;
    }

    public CloseableHttpClient getHttpClient() {
        return httpClient;
    }


    public static String postMapToHttp(
            String url,
            Map params,
            int conTimeOut,
            int socketTimeOut,
            Map header
            ){
        CloseableHttpClient httpClient = httpConnectionManager.getHttpClient();
        HttpPost httpPost = new HttpPost(url);
        if(null != header && !header.isEmpty()){
            for (Map.Entry entry : header.entrySet()) {
                httpPost.addHeader(entry.getKey(), entry.getValue());
            }
        }
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(conTimeOut)
                .setConnectTimeout(conTimeOut).setSocketTimeout(socketTimeOut).build();
        httpPost.setConfig(requestConfig);
        List paramList = generatNameValuePair(params);

        CloseableHttpResponse response = null;
        try {
            httpPost.setEntity(new UrlEncodedFormEntity(paramList, "utf-8"));
            response = httpClient.execute(httpPost);
            //请求发生异常时,手动关闭连接
            if (response.getStatusLine ().getStatusCode () != 200) {  
                httpPost.abort();  
                return null;  
            } 
            HttpEntity entity =response.getEntity();  
            //EntityUtils.toString inPutStream close
            String result = EntityUtils.toString(entity, "utf-8");
            return result;
        } catch (ClientProtocolException e) {
            logger.error("http发生异常1:" + CommonUntil.getErrorInfoFromException(e));
            httpPost.abort();
            return null;  
        } catch (IOException e) {
            logger.error("http发生异常2:" + CommonUntil.getErrorInfoFromException(e));
            httpPost.abort();
            return null;  
        }finally {
            try {
                if (response != null)
                    response.close();
            } catch (IOException e) {
                logger.error("http发生异常3:" + CommonUntil.getErrorInfoFromException(e));
            }
        }
    }


    /**
     * 请求数据为:XML字符串
     */
    public static String postXmlToHttp(
            String url,
            String paramXml,
            int conTimeOut,
            int socketTimeOut,
            Map header
            ){
        CloseableHttpClient httpClient = httpConnectionManager.getHttpClient();
        HttpPost httpPost = new HttpPost(url);
        if(null != header && !header.isEmpty()){
            for (Map.Entry entry : header.entrySet()) {
                httpPost.addHeader(entry.getKey(), entry.getValue());
            }
        }
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(conTimeOut)
                .setConnectTimeout(conTimeOut).setSocketTimeout(socketTimeOut).build();
        httpPost.setConfig(requestConfig);
        CloseableHttpResponse response = null;
        try {
            StringEntity se = new StringEntity(paramXml, "utf-8");
            httpPost.setEntity(se);
            response = httpClient.execute(httpPost);
            //请求发生异常时,手动关闭连接
            if (response.getStatusLine ().getStatusCode () != 200) {  
                httpPost.abort();  
                return null;  
            } 
            HttpEntity entity =response.getEntity();  
            //EntityUtils.toString inPutStream close
            String result = EntityUtils.toString(entity, "utf-8");
            return result;
        } catch (ClientProtocolException e) {
            logger.error("http发生异常1:" + CommonUntil.getErrorInfoFromException(e));
            httpPost.abort();
            return null;  
        } catch (IOException e) {
            logger.error("http发生异常2:" + CommonUntil.getErrorInfoFromException(e));
            httpPost.abort();
            return null;  
        }finally {
            try {
                if (response != null)
                    response.close();
            } catch (IOException e) {
                logger.error("http发生异常3:" + CommonUntil.getErrorInfoFromException(e));
            }
        }
    }

    /**
     * MAP类型数组转换成NameValuePair类型
     * @param properties  MAP类型数组
     * @return NameValuePair类型数组
     */
    private static List generatNameValuePair(Map properties) {
        ArrayList nameValuePair = new ArrayList(properties.size());
        for (Map.Entry entry : properties.entrySet()) {
            nameValuePair.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }
        return nameValuePair;
    }

    /**
     * 获取请求头
     * @return
     */
    public static Map getDefaultHeaders(){
        Map header = new HashMap<>();
        header.put("Content-Type", "text/html");
        header.put("Accept-Charset", "utf-8");
        header.put("User-Agent", "Mozilla/4.0");
        return header;
    }
}
最后说两句

1.注意调整相关连接池参数;
2.连接池可以实现线程保活,静态路由等,由于代码只是个demo,所有没有详细给出,想了解可以查阅我上文贴出的相关文章链接,里面资料有说到,这里我就不把事情搞复杂了。

你可能感兴趣的:(随笔,httpclient,http连接,实例)