zoukankan      html  css  js  c++  java
  • 连接管理

    HttpClient 有一个对连接初始化和终止,还有在活动连接上 I/O 操作的完整控制。而连接操作的很多方面可以使用一些参数来控制。

    一、套接字工厂

    HttpClientContext clientContext = HttpClientContext.create();
    /**
     * 连接套接字 依靠 ConnectionSocketFactory接口去创建、初始化、连接。
     * ConnectionSocketFactory
     *      PlainConnectionSocketFactory 是创建和初始化原生(非加密的)套接字的默认工厂类。
     *      LayeredConnectionSocketFactory 也是一个接口, 是 ConnectionSocketFactory接口的扩展
     *      SSLConnectionSocketFactory SSL/TLS层的连接套接字, 可以建立SSL连接。
     * 注:HttpClient不适用任何自定义的加密功能,它完全依赖于标准的Java Cryptography(JCE) 和 安全套接字扩展(JSEE)。
     */
    PlainConnectionSocketFactory sf = PlainConnectionSocketFactory.getSocketFactory();
    
    // 创建并初始化套接字
    Socket socket = sf.createSocket(clientContext);
    
    int timeout = 1000;// ms
    HttpHost target = new HttpHost("localhost");
    InetSocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", 8888);
    // 连接套接字
    sf.connectSocket(timeout, socket, target, remoteAddress, null,
            clientContext);
    
    //套接字连接成功后,就可以使用Socket读写数据了, 一般不仅仅是读写数据,如果这样,比纯粹使用Socket网络编程还麻烦
    // 获取输出流:OutputStream outputStream = socket.getOutputStream();
    // 获取输入流:InputStream inputStream = socket.getInputStream();

    二、SSL/TLS 的定制

    SSL证书,也称为服务器SSL证书,是遵守SSL协议的一种数字证书由全球信任的证书颁发机构(CA)验证服务器身份后颁发将SSL证书安装在网站服务器上,可实现网站身份验证和数据加密传输双重功能。

    /**
     * 使用带证书的定制 SSL访问
     * 程序中使用了my.store这个文件,这个文件不是网站的证书,而是一份包含自己密码的自己的证书库。
     * 这个文件是需要自己生成的,使用jdk中的keytool命令可以很方便的生成my.store文件。
     * 如何生成文件,请查看:https://www.cnblogs.com/myitnews/p/12206094.html
     */
    public void createHttpSSL() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, IOException, CertificateException {
         //是否绕过SSL
         boolean isSSL = false;
         //证书
         File creFile = new File("C:\Users\Administrator\Desktop\my.store");
         //证书库密码, 生成my.store时输入的口令
         String crePwd = "mypassword";
         /**
          * 1. 创建 SSL上下文对象
          */
         SSLContext sslContext = null;
         if (!isSSL) {
             sslContext = SSLContext.getInstance("SSLv3");
             // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
             X509TrustManager x509TrustManager = new X509TrustManager() {
                 @Override
                 public X509Certificate[] getAcceptedIssuers() {
                     return null;
                 }
                 @Override
                 public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                 }
                 @Override
                 public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                 }
             };
             sslContext.init(null, new TrustManager[] {x509TrustManager}, null);
         } else {
             if (null != creFile && creFile.length() > 0) {
                 if (null != crePwd) {
                     KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                     keyStore.load(new FileInputStream(creFile), crePwd.toCharArray());
                     sslContext = SSLContexts.custom().loadTrustMaterial(keyStore, new TrustSelfSignedStrategy()).build();
                 } else {
                     throw new SSLHandshakeException("密码为空");
                 }
             }
         }
    
         /**
          * 2. 注册
          */
         Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                 .register("http", PlainConnectionSocketFactory.INSTANCE)
                 .register("https", new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.getDefaultHostnameVerifier()))
                 .build();
    
         /**
          * 3. SSL注册到连接管理器中
          */
         PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);
         connManager.setMaxTotal(1000);  // 连接池最大连接数
         connManager.setDefaultMaxPerRoute(20);  // 每个路由最大连接数
    
         /**
          * 4. 发送请求
          */
         CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connManager).build();
         //12306:https://kyfw.12306.cn/otn/login/init
         //支付宝:https://www.alipay.com/, 这里如果使用HttpPost会报403
         HttpGet httpPost = new HttpGet("https://www.alipay.com/");
         CloseableHttpResponse response = httpClient.execute(httpPost);
         System.out.println("响应行:" + response.getStatusLine());
         System.out.println("响应内容:"+EntityUtils.toString(response.getEntity(), Consts.UTF_8));
     }

    三、主机名验证

    /**
     * 主机名验证
     * 除了在 SSL/TSL协议层扮演信任验证和客户端认证角色之外,HttpClient能选择性的去验证
     * 目标主机名称是否和储存在服务器中X.509证书上的名称一致。一旦连接已经建立,验证过程能提供服务器信任材料的额外可靠性保证。
     * javax.net.ssl.HostnameVerifier接口体现了一种主机名验证策略。
     * javax.net.ssl.HostnameVerifier有两种实现HttpClient可以用来工作:
     *      DefaultHostnameVerifier:默认实现,遵从RFC2818。主机名必须符合指定证书上任意备选名称。
     *      NoopHostnameVerifier:该主机名验证器本质上会关闭主机名验证。它接受任何有效的和符合目标主机的SSL会话。
     *
     * 注意:主机名验证和 SSL信任验证不可混淆。
     */
    public void hostVerifier() throws IOException {
        //每一个HttpClient会使用默认的DefaultHostnameVerifier实现,如果你想也可以指定实现
        //SSLContext sslContext = SSLContexts.createSystemDefault();
        //SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
        //HttpClients.custom().setSSLSocketFactory(sslsf);
    
        //HttpClient 4.4版本使用公共后缀列表来保证SSL证书中的通配符不会被误用,当应用在有一个共同顶级域名下的子域名的时候。
        //参考:https://publicsuffix.org/list/effective_tld_names.dat】。强烈建议制作一个列表的本地副本。
    
        PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader.load(
                PublicSuffixMatcher.class.getResource("my-copy-effective_tld_names.dat"));
        DefaultHostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher);
        // 禁用公共后缀验证
        // DefaultHostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(null);
    
        HttpClientBuilder clientBuilder = HttpClients.custom();
        //绑定主机验证
        clientBuilder.setSSLHostnameVerifier(hostnameVerifier);
    
        CloseableHttpClient httpClient = clientBuilder.build();
    }
  • 相关阅读:
    C#添加修改删除文件文件夹大全
    实用且不花哨的js代码大全
    vs2005 2008快捷键
    C#:String.Format数字格式化输出
    获取农历日期
    Vim 常用快捷键
    一个简单的makefile示例及其注释
    nginx源码剖析(1)概要
    利用Vim 打造开发环境(一)>Linux 字符界面 vim的配置
    Ubuntu 9.10设置摘要
  • 原文地址:https://www.cnblogs.com/myitnews/p/12204889.html
Copyright © 2011-2022 走看看