httpClient 4.5 线程池 同时支持https和http

工作中经常遇到要发送https请求情况,一般都有自己的工具包,很多过时的方法都被打了@Deprecated这个鬼东西,导致代码上面总是出现那个又大又粗的黑线,看着都头疼
我写这篇文章的时候,最新的版本是4.5.2

    
        org.apache.httpcomponents
        httpclient
        4.5.2
    

首先要实现2个接口X509TrustManager,HostnameVerifier

X509TrustManager:用来读取公钥做验证加密数据传输的。如何导出公钥请参考“
http://blog.csdn.net/mzh1992/article/details/53887321
HostnameVerifier:就好理解多了,从字面上就能看出来,是用来验证host的
X509TrustManager:

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

/**
 * Created by mazhenhua on 2016/12/23.
 */
public class MyX509TrustManager implements X509TrustManager {
    private Certificate cert = null;

    public MyX509TrustManager() {
        try {
            FileInputStream fis = new FileInputStream(
                    "C:\\Users\\mazhenhua\\Desktop\\cert\\test.cer");
            BufferedInputStream bis = new BufferedInputStream(fis);

            CertificateFactory cf = CertificateFactory.getInstance("X.509");

            while (bis.available() > 0) {
                cert = cf.generateCertificate(bis);
                System.out.println(cert.toString());
            }
            bis.close();
        } catch (Exception e) {

        }
    }

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
    }

    @Deprecated
    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        for (X509Certificate cert : chain) {
            if (cert.toString().equals(this.cert.toString()))
                return;
        }
        throw new CertificateException("certificate is illegal");
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[] { (X509Certificate) cert };
    }
}

如果没有证书,或者忽略证书的那种请求,就直接实现,啥都不用动不写,就OK了!!

HostnameVerifier:

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;

/**
 * Created by mazhenhua on 2016/12/23.
 */
public class MyVerifyHostname implements HostnameVerifier {

    @Override
    public boolean verify(String arg0, SSLSession arg1) {
        if (arg0.equals("127.0.0.1") || arg0.equals("mazhenhua.com"))
            return true;
        else
            return false;
    }
}

重点来了HttpClientPool

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.MessageConstraints;
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.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

/**
 * Created by mazhenhua on 2016/12/23.
 */
public class HttpClientPool {


    private String host;
    private String cookie;
    private String path;
    private int port;
    private SSLContext sslContext;
    private X509TrustManager tm;
    private HttpClient httpClient;
    private Registry registry;
    private ConnectionSocketFactory plainSF;
    private LayeredConnectionSocketFactory sslSF;



    int            maxPerRoute              = 15;     // 每个路由允许活跃连接数
    int            maxTotal                 = 100;    // 所有路由总连接数上限
    int            maxLineLength            = 0;     // 每一个请求行的最大行长度(坑已踩)
    int            connectionRequestTimeout = 1000000000;  // 向连接池申请连接超时,单位:毫秒
    int            connectTimeout           = 6000;   // 建立连接超时,单位:毫秒
    int            socketTimeout            = 10000;  // 等待数据超时,单位:毫秒

    public HttpClientPool(String host, String cookie, String path, int port)
            throws Exception {
        this.host = host;
        this.cookie = cookie;
        this.path = path;
        this.port = port;
        sslContext = SSLContext.getInstance("TLS");
        tm = new MyX509TrustManager(); // 那个读取公钥的实现类
        sslContext.init(null, new TrustManager[] { tm },
                new java.security.SecureRandom());

        /* 不使用连接次
        httpClient = HttpClients.custom()
                .setSSLHostnameVerifier(new MyVerifyHostname())
                .setSSLContext(sslContext).build();*/


        /** 以下是连接池区域 具体的参数,可以根据情况自己调整**/
        sslSF = new SSLConnectionSocketFactory(sslContext, new MyVerifyHostname()); // 验证host的那个
        RegistryBuilder registryBuilder = RegistryBuilder
                . create();
        plainSF = new PlainConnectionSocketFactory();
        registryBuilder.register("http", plainSF);
        registryBuilder.register("https", sslSF);
        registry = registryBuilder.build();
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(
                registry);
        connManager.setDefaultMaxPerRoute(maxPerRoute);
        connManager.setMaxTotal(maxTotal);
        ConnectionConfig connConfig = ConnectionConfig
                .custom()
                .setMessageConstraints(
                        MessageConstraints.custom().setMaxLineLength(maxLineLength).build()).build();
        connManager.setDefaultConnectionConfig(connConfig);

        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();

        httpClient = HttpClients.custom().setConnectionManager(connManager)
                .setDefaultRequestConfig(requestConfig).build();
    }

    public String sendPost(String localPath, String filename)
            throws URISyntaxException, ClientProtocolException, IOException {

        URI uri = new URIBuilder().setScheme("https").setHost(host)
                .setPath(path).setParameter("filename", filename).setPort(port)
                .build();
        HttpPost httpPost = new HttpPost(uri);
        /**这个部分是支持带上传的*/
        FileEntity fileEntity = new FileEntity(new File(localPath));
        //fileEntity.setChunked(true);
        //httpPost.setEntity(fileEntity);
        httpPost.addHeader("Cookie", cookie);
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(20000).build();//设置请求和传输超时时间
        httpPost.setConfig(requestConfig);
        HttpResponse response = httpClient.execute(httpPost);
        HttpEntity httpEntity = response.getEntity();
        httpEntity = new BufferedHttpEntity(httpEntity);
        String resultString = EntityUtils.toString(httpEntity);
        return resultString;
    }

    public static void main(String[] args) {
        try {
            HttpClientPool test = new HttpClientPool(
                    "127.0.0.1",
                    null,
                    "/post/index.htm", 8443);
            String resultString = test.sendPost(null, null);
            System.out.println(resultString);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

上面这个类中httpClient连接池支持发送http和https两种,发请求的时候不用再关心到底是https还是http

终于看不到那个个过时提醒的那个黑线了。

你可能感兴趣的:(https)