龙空技术网

程序员的福音 - Apache Commons HttpClient

菜鸟码农的Java笔记 172

前言:

眼前各位老铁们对“apachecommons学习”可能比较关注,咱们都需要了解一些“apachecommons学习”的相关知识。那么小编在网上搜集了一些对于“apachecommons学习””的相关资讯,希望我们能喜欢,同学们一起来学习一下吧!

此文是系列文章第十篇,前几篇请点击链接查看

程序员

程序员的福音 - Apache Commons Lang

程序员的福音 - Apache Commons IO

程序员的福音 - Apache Commons Codec

程序员的福音 - Apache Commons Compress

程序员的福音 - Apache Commons Exec

程序员的福音 - Apache Commons Email

程序员的福音 - Apache Commons Net

程序员的福音 - Apache Commons Collections

Apache HttpClient 组件是为扩展而设计的,同时提供对基本HTTP协议的强大支持。

java.net包提供了通过HTTP访问资源的基本功能,但它并没有提供许多应用程序所需的全部灵活性或功能。HttpClient 组件通过提供一个高效、最新、功能丰富的包来填补这一空白,该包实现了最新HTTP标准的客户端。

HttpClient 过去是 Commons 的一部分,现在是 Apache HttpComponents 的一部分。Apache HttpComponents 是 Apache 的顶级项目,负责创建和维护专注于 HTTP 和相关协议的 Java 组件工具集。因此文章后面将不再使用 Commons HttpClient 字样,而是使用 HttpClient 。

HttpClient 目前有三个大版本,他们是不兼容的,可以同时存在。HttpClient 3过去是 Commons 的一部分,所以一般来说看到 Apache HttpClient 3 的说法指的就是 Commons HttpClient,所属包 org.apache.commons.httpclient,maven 依赖如下

<!-- HttpClient 3 --><dependency>    <groupId>commons-httpclient</groupId>    <artifactId>commons-httpclient</artifactId>    <version>3.1</version></dependency>

HttpClient 4 指的是 Apache HttpComponents 下的项目,所属包 org.apache.http,maven 依赖如下

<!-- HttpClient 4 --><dependency>    <groupId>org.apache.httpcomponents</groupId>    <artifactId>httpclient</artifactId>    <version>4.5.13</version></dependency>

HttpClient 5 指的是 Apache HttpComponents 下的最新项目,包结构是 org.apache.hc,依赖如下

<dependency>    <groupId>org.apache.httpcomponents.client5</groupId>    <artifactId>httpclient5</artifactId>    <version>5.1</version></dependency>

HttpClient 3 早已不在维护,推荐使用最新的HttpClient 5,截止本文发布时间 2021-08-13,HttpClient 5 在前5天还发布了新版本。HttpClient 5 支持(经典API)(异步API)(反应式API)。

HttpClient 目前最新版本是 5.1,最低要求 Java8 以上。下面我将简单介绍下这几个版本 HttpClient 的用法。

01

原生API

我们先来看看如果不使用 HttpClient 而是使用 Java 原生 API,写一个 http 请求的例子

HttpsURLConnection conn = null;try {    URL url = new URL(";);    conn = (HttpsURLConnection) url.openConnection();    // https请求需要设置证书,为了简单此处默认信任服务器不做证书校验    SSLContext sc = SSLContext.getInstance("SSL");    sc.init(null, new TrustManager[]{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];        }    }}, new java.security.SecureRandom());    conn.setSSLSocketFactory(sc.getSocketFactory());    conn.setHostnameVerifier((s, sslSession) -> true);    conn.setRequestMethod("GET");    conn.setConnectTimeout(5000);    conn.setReadTimeout(5000);    conn.setUseCaches(false);    conn.connect();    InputStream is = conn.getInputStream();    try (BufferedReader br = new BufferedReader(            new InputStreamReader(is))) {        StringBuilder sb = new StringBuilder();        String line;        while ((line = br.readLine()) != null) {            sb.append(line).append("\n");        }        sb.deleteCharAt(sb.length() - 1);        println(sb.toString());    }} catch (Exception e) {    e.printStackTrace();} finally {    if (conn != null) {        conn.disconnect();    }}

我们看到这个例子是一个相对比较简单的 https 的 get请求,没有参数。代码已经比较复杂了,如果是 post 请求,需要传递参数,需要保存cookie(有些请求需求登录,我们还要先模拟登录请求后手动将 cookie 保存下来,下次请求再把 cookie 设置上)等场景代码将更为复杂。并且原生 API 默认不支持异步不支持响应式等,这时候就轮到 HttpClient 大显手身了。

02

HttpClient 3

HttpClient 3 由于早已不在维护,不支持 http2 和异步等特性,此处只做一个最简单的示例给大家了解一下。注意所属包是 org.apache.commons.httpclient

// httpClient对象是线程安全的,可以单例使用,提升性能HttpClient httpClient = new HttpClient();// 设置连接超时 和 socket超时httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(2000);httpClient.getHttpConnectionManager().getParams().setSoTimeout(5000); // 响应超时HttpMethod getM = new GetMethod(";);// 设置请求头getM.setRequestHeader("Content-Type", "application/json");NameValuePair p1 = new NameValuePair("name", "zs");NameValuePair p2 = new NameValuePair("age", "11");// 设置查询参数,相当于 ?name=zs&age=11getM.setQueryString(new NameValuePair[]{p1, p2});try {    int code = httpClient.executeMethod(getM);    if (code == HttpStatus.SC_OK) {        // 获取结果字符串        String res = getM.getResponseBodyAsString();        // InputStream res = getM.getResponseBodyAsStream(); // 也可以转换为流        System.out.println(res);    } else {        System.err.println("请求失败,状态码:" + code);    }} catch (IOException e) {    e.printStackTrace();} finally {    // 释放连接资源    getM.releaseConnection();}

03

HttpClient 4

HttpClient 4 也不是最新版本,此处也只做一个最简单的示例给大家了解一下。注意所属包是 org.apache.http

// httpClient对象是线程安全的,可以单例使用,提升性能CloseableHttpClient httpClient = HttpClientBuilder.create().build();HttpGet httpGet = new HttpGet(";);httpGet.setHeader("Content-Type", "application/json");RequestConfig requestConfig = RequestConfig.custom()        .setConnectTimeout(2000) // 连接超时        .setConnectionRequestTimeout(2000) // 请求超时        .setSocketTimeout(2000) // 响应超时        .build();httpGet.setConfig(requestConfig);try (CloseableHttpResponse res = httpClient.execute(httpGet)) {    int code = res.getStatusLine().getStatusCode();    if (code == HttpStatus.SC_OK) {        HttpEntity entity = res.getEntity();        println(EntityUtils.toString(entity, "UTF-8"));    } else {        System.err.println("请求失败,状态码:" + code);    }} catch (IOException e) {    System.err.println("请求异常");} finally {    httpGet.reset();    // httpGet.releaseConnection(); // 等价于reset()}

04

HttpClient 5

HttpClient 5 是目前最新版本。下面将着重介绍下。注意所属包是 org.apache.hc。HttpClient 5 除了包名和 HttpClient 4 有所区别,API的用法大体类似,只有小部分不一致。

建议将 httpClient 作为单例使用,所有请求共用一个 httpClient 对象,这样可以保存 HTTP 的状态,比如登录状态等

1. post请求

// httpClient对象是线程安全的,可以单例使用,提升性能CloseableHttpClient httpClient = HttpClients.createDefault();HttpPost httpPost = new HttpPost(";);RequestConfig requestConfig = RequestConfig.custom()        .setConnectTimeout(Timeout.ofSeconds(2))        .setConnectionRequestTimeout(Timeout.ofSeconds(2))        .setResponseTimeout(Timeout.ofSeconds(2))        .build();httpPost.setConfig(requestConfig);httpPost.setVersion(HttpVersion.HTTP_2); // 支持http2httpPost.setHeader("Content-Type", "application/json");// 支持多种entity参数,字节数组,流,文件等等// 此处使用restful的"application/json",所以传递json字符串httpPost.setEntity(new StringEntity(JSON.toJSONString(paramsObj)));try (CloseableHttpResponse res = httpClient.execute(httpPost)) {    if (res.getCode() == HttpStatus.SC_OK) {        HttpEntity entity = res.getEntity();        println(EntityUtils.toString(entity));    } else {        System.err.println("请求失败,状态码:" + res.getCode());    }} catch (Exception e) {    e.printStackTrace();} finally {    // 释放连接资源    httpPost.reset();}

2. 重定向支持

有些服务器在可能会返回一个重定向的响应,状态码为302或301,如果是浏览器则会自动向重定向地址发起http请求,HttpClient 5 同样支持此功能,示例如下

CloseableHttpClient httpClient = HttpClients.custom()        .disableAutomaticRetries() //关闭自动重试        .setRedirectStrategy(DefaultRedirectStrategy.INSTANCE)        .build();// ... ...

3. 异步支持

异步 API 的好处就不说了,HttpClient 5 异步 API 使用 NIO,可以使用少量的线程支持大量的并发,在并发量较大的情况下依然可以保持服务的稳定性和吞吐量。下面看一个简单的例子

CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault();SimpleHttpRequest request = SimpleHttpRequest.create(Method.GET.name(), ";);httpClient.start();httpClient.execute(request, new FutureCallback<SimpleHttpResponse>() {    @Override    public void completed(SimpleHttpResponse result) {        // 响应成功        println(result.getBodyText());        IOUtils.closeQuietly(httpClient);    }    @Override    public void failed(Exception ex) {        // 响应出错        ex.printStackTrace();        IOUtils.closeQuietly(httpClient);    }    @Override    public void cancelled() {        // 响应取消        println("cancelled");        IOUtils.closeQuietly(httpClient);    }});// ... ... 做其他业务处理

05

总结

HttpClient 作为 Java HTTP 客户端的工具类,API简单易懂,大大简化了Java HTTP 发送程序的复杂度,并且自动支持 Cookie 功能,GZip 解析,重定向支持,异步支持等等,用来代替 Java 自带的 API 是个不错的选择。

后续章节我将继续给大家介绍 commons 中其他好用的工具类库,期待你的关注。

标签: #apachecommons学习