httpClient4.5使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/woaiqianzhige/article/details/81463266

1.基本使用

public class TestHttpClient {

    public static void main(String[] args) throws IOException {
        String url = "http://www.youku.com";
        CloseableHttpClient client = HttpClients.custom().build();
        HttpGet get = new HttpGet(url);
        String s = client.execute(get, new myResponse());
        System.out.println(s);
        client.close();
    }

    /*用于处理响应的泛型类*/
    static class myResponse implements ResponseHandler<String> {
        @Override
        public String handleResponse(HttpResponse httpResponse) throws IOException {
            HttpEntity entity = httpResponse.getEntity();
            if (entity != null) {
                String s = EntityUtils.toString(entity);
                return s;
            }
            return null;
        }
    }
}

httpclient的第二个参数接受一个responseHandler的泛型类,泛型是返回值类型,使用这种方法不需要手动关闭response,下面代码会自动帮忙关闭。下面是执行方法的源码,自动关闭在倒数第二行。

 public <T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context) throws IOException, ClientProtocolException {
        Args.notNull(responseHandler, "Response handler");
        CloseableHttpResponse response = this.execute(target, request, context);

        Object result;
        try {
            result = responseHandler.handleResponse(response);
        } catch (Exception var11) {
            HttpEntity entity = response.getEntity();

            try {
                EntityUtils.consume(entity);
            } catch (Exception var10) {
                this.log.warn("Error consuming content after an exception.", var10);
            }

            if (var11 instanceof RuntimeException) {
                throw (RuntimeException)var11;
            }

            if (var11 instanceof IOException) {
                throw (IOException)var11;
            }

            throw new UndeclaredThrowableException(var11);
        }

        HttpEntity entity = response.getEntity();
        EntityUtils.consume(entity);
        return result;
    }

2.访问https的网址。

https网址是通过tls加密的,所以我们要自定义证书验证器,这里我们允许所有的证书通过,创建新的空证书验证器并将它设置到httpclent上即可。

 public static void main(String[] args) throws IOException, KeyManagementException, NoSuchAlgorithmException {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new X509TrustManager[]{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 new X509Certificate[0];
            }
        }}, null);

        String url = "https://www.baidu.com";
        CloseableHttpClient client = HttpClients.custom().setSSLContext(sslContext).build();
        HttpGet get = new HttpGet(url);
        String s = client.execute(get, new myResponse());
        System.out.println(s);
        client.close();
    }

    /*用于处理响应的泛型类*/
    static class myResponse implements ResponseHandler<String> {
        @Override
        public String handleResponse(HttpResponse httpResponse) throws IOException {
            HttpEntity entity = httpResponse.getEntity();
            if (entity != null) {
                String s = EntityUtils.toString(entity);
                return s;
            }
            return null;
        }
    }

初始化一个的SSLContext,并初始化它,我们这里选择的是

 SSLContext.getInstance("TLS"); TLS版本,TLS版本还可以选择 “TLSv1.1”  “TLSv1.2”  如果遇到返回协议版本错误的提示,说明和目标网站的协议版本不一致,可能是版本低了,我曾经遇到过这样的问题,把TLS换成TLSv1.2就能正常访问了。

3.多线程使用。

httpclient是线程安全的,我们没必要调用一次就创建一个httpclient对象,整个系统中只需要存在一个httpclient就行了。一般封装成工具类使用,我们用静态static关键字修饰httpclent即可。

网上有人说创建httpclient时传入poolinghttpClientConnectionmanager,我觉着是没必要的。

 PoolingHttpClientConnectionManager pm = new PoolingHttpClientConnectionManager();
        pm.setMaxTotal(200);
        CloseableHttpClient client = HttpClients.custom().setSSLContext(sslContext).setConnectionManager(pm).build();

类似于上面这种用法,这种用法有两个问题,

1.在稍微老版本的httpclient中(4.3.*吧),如果我们设置了 SSLContext并且SSLContext.getInstance("TLSv1.2");这样创建的,那创建的链接池是不能自动变成TLSv1.2的,它获得的链接还是TLS,有些必须要求TLSv1.2的网站不能正常访问,

除非创建PoolingHttpClientConnectionManager时指定SSLContext为TLSv1.2,类似于这种创建方法

 Registry<ConnectionSocketFactory> build = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", new SSLConnectionSocketFactory(sslContext)).build();
        PoolingHttpClientConnectionManager pm = new PoolingHttpClientConnectionManager(build);
        pm.setMaxTotal(200);
        CloseableHttpClient client = HttpClients.custom().setSSLContext(sslContext).setConnectionManager(pm).build();

上面这样长长的调用方法并不舒服。

2.不传入PoolingHttpClientConnectionManager会怎样?

我们在client的build方法中可以看到

如果我们没传入连接池,他会自动的创建一个链接池,并且创建的连接池是使用我们传入的sslcontext创建的,所以我们的协议版本他是支持的。

猜你喜欢

转载自blog.csdn.net/woaiqianzhige/article/details/81463266