百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

程序员的福音 - Apache Commons HttpClient

toyiye 2024-07-11 00:42 22 浏览 0 评论


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

程序员

程序员的福音 - 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("https://xxx/");
    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("http://xxx/");
// 设置请求头
getM.setRequestHeader("Content-Type", "application/json");
NameValuePair p1 = new NameValuePair("name", "zs");
NameValuePair p2 = new NameValuePair("age", "11");
// 设置查询参数,相当于 ?name=zs&age=11
getM.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("http://xxx/?name=zs&age=11");
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("https://xxx/");
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); // 支持http2
httpPost.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(), "https://xxx/");
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 中其他好用的工具类库,期待你的关注。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码