Apache HttpClient5 介绍及快速入门示例

HttpClient 概述

超文本传输协议 (HTTP) 可能是当今 Internet 上使用的最重要的协议。Web服务、支持网络的设备以及网络计算的增长继续扩大了 HTTP 的作用 协议,同时增加了需要 HTTP 支持的应用程序数量。

尽管 java.net 包提供了通过 HTTP 访问资源的基本功能,但它并未提供完整的 许多应用程序所需的灵活性或功能。HttpClient 试图通过提供高效的 最新且功能丰富的包,用于实现最新 HTTP 标准和建议的客户端。

HttpClient HttpClient专为扩展而设计,同时为基础HTTP协议提供强大的支持,任何构建HTTP感知客户端应用程序的人都可能感兴趣,例如web浏览器、web服务客户端或利用或扩展HTTP协议进行分布式通信的系统。

特征

  • 基于标准的纯 Java,HTTP 版本 1.0、1.1、2.0 的实现(仅限异步 API)
  • 支持使用 HTTPS (HTTP over SSL) 协议进行加密。
  • 可插拔套接字工厂和 TLS 策略。
  • 通过 HTTP/1.1 和 HTTP/1.0 代理进行透明消息交换。
  • 通过 CONNECT 方法通过 HTTP/1.1 和 HTTP/1.0 代理建立隧道 HTTPS 连接。
  • Basic、Digest、Bearer 身份验证方案。
  • HTTP 状态管理和 Cookie 支持。
  • 灵活的连接管理和池化。
  • 支持 HTTP 响应缓存。
  • 源代码在 Apache 许可证下免费提供。

标准合规性

HttpClient 努力遵守 Internet 工程任务组 (IETF) 认可的以下规范,以及 整个互联网:

  • RFC 9110 - HTTP 语义
  • RFC 9111 - HTTP 缓存
  • RFC 9112 - 超文本传输协议版本 1.1 (HTTP/1.1)
  • RFC 7540 - 超文本传输协议版本 2 (HTTP/2)
  • RFC 7541 - HPACK:HTTP/2 的标头压缩
  • RFC 1945 - 超文本传输协议 -- HTTP/1.0
  • RFC 2396 - 统一资源标识符 (URI):泛型语法
  • RFC 6265 - HTTP 状态管理机制 (Cookie)
  • RFC 7616 - HTTP 摘要访问身份验证
  • RFC 7617 - HTTP"基本"身份验证方案
  • RFC 5861 - 过时内容的 HTTP 缓存控制扩展

HttpClient5相对早期版本的优势

早期版本劣势

1. 同步阻塞,效率低下

早期的HttpClient(比如Apache HttpClient 4.x)主要是同步的,这意味着每次发起请求时,线程都会被挂起,直到服务器响应。在高并发场景下,这种阻塞式调用会严重拖慢应用的性能,导致资源利用率低下。

2. 配置复杂,易出错

配置HttpClient可不是件简单事儿。连接超时、请求超时、套接字超时,还有各种各样的HTTP头设置,稍不注意就可能踩坑。更别提SSL/TLS配置了,简直是新手程序员的噩梦。

3. API过时,维护成本高

随着Java版本的迭代,一些老的HttpClient API显得越来越过时。它们可能不支持最新的Java特性,比如Lambda表达式、Stream API等,这使得代码维护起来异常艰难。而且,随着新特性的加入,老版本的HttpClient往往需要打补丁,增加了维护成本。

4. 安全性隐患

网络安全日益重要,而老版本的HttpClient在安全性方面可能存在漏洞。比如,对SSL/TLS协议的支持可能不够全面,容易受到中间人攻击或数据泄露的风险。

新版本优势

1、异步支持

HttpClient 5原生支持异步和响应式编程,这意味着你可以在不阻塞线程的情况下发起HTTP请求,大大提高了应用的并发性能。

2、简化配置

相比老版本,HttpClient 5的配置更加直观和灵活。你可以通过构建器模式轻松设置各种参数,减少了配置错误的可能性。

3、增强安全性

HttpClient 5对SSL/TLS协议的支持更加全面,默认启用了更安全的加密套件和协议版本,提升了数据传输的安全性。

HttpClient5 快速入门

  • 下载最新 HttpClient 5.4 版本的"二进制"包,或使用您选择的依赖项管理器配置依赖项.

  • HttpClient 5.4 需要 Java 1.8 或更高版本。

Maven引入依赖

XML 复制代码
        <dependency>
            <groupId>org.apache.httpcomponents.client5</groupId>
            <artifactId>httpclient5</artifactId>
            <version>5.4.1</version>
        </dependency>

使用示例

  • 以下代码片段说明了如何使用 HttpClient 本机 API 执行 HTTP GET 和 POST 请求。
java 复制代码
try (CloseableHttpClient httpclient = HttpClients.createDefault()) {

    ClassicHttpRequest httpGet = ClassicRequestBuilder.get("http://httpbin.org/get")
            .build();

    // The underlying HTTP connection is still held by the response object
    // to allow the response content to be streamed directly from the network socket.
    // In order to ensure correct deallocation of system resources
    // the user MUST call CloseableHttpResponse#close() from a finally clause.
    // Please note that if response content is not fully consumed the underlying
    // connection cannot be safely re-used and will be shut down and discarded
    // by the connection manager.
    httpclient.execute(httpGet, response -> {
        System.out.println(response.getCode() + " " + response.getReasonPhrase());
        final HttpEntity entity1 = response.getEntity();
        // do something useful with the response body
        // and ensure it is fully consumed
        EntityUtils.consume(entity1);
        return null;
    });

    ClassicHttpRequest httpPost = ClassicRequestBuilder.post("http://httpbin.org/post")
            .setEntity(new UrlEncodedFormEntity(Arrays.asList(
                    new BasicNameValuePair("username", "vip"),
                    new BasicNameValuePair("password", "secret"))))
            .build();

    httpclient.execute(httpPost, response -> {
        System.out.println(response.getCode() + " " + response.getReasonPhrase());
        final HttpEntity entity2 = response.getEntity();
        // do something useful with the response body
        // and ensure it is fully consumed
        EntityUtils.consume(entity2);
        return null;
    });
}
  • 可以使用更简单但不太灵活、流畅的 API 来执行相同的请求。
java 复制代码
// The fluent API relieves the user from having to deal with manual deallocation of system
// resources at the cost of having to buffer response content in memory in some cases.

Request.Get("http://targethost/homepage")
    .execute().returnContent();

Request.Post("http://targethost/login")
    .bodyForm(Form.form().add("username",  "vip").add("password",  "secret").build())
    .execute().returnContent();
  • 以下代码片段说明了如何使用 HttpClient 异步 API 执行 HTTP 请求。
java 复制代码
try (CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault()) {
    // Start the client
    httpclient.start();

    // Execute request
    SimpleHttpRequest request1 = SimpleRequestBuilder.get("http://httpbin.org/get").build();
    Future<SimpleHttpResponse> future = httpclient.execute(request1, null);
    // and wait until response is received
    SimpleHttpResponse response1 = future.get();
    System.out.println(request1.getRequestUri() + "->" + response1.getCode());

    // One most likely would want to use a callback for operation result
    CountDownLatch latch1 = new CountDownLatch(1);

    SimpleHttpRequest request2 = SimpleRequestBuilder.get("http://httpbin.org/get").build();

    httpclient.execute(request2, new FutureCallback<SimpleHttpResponse>() {

        @Override
        public void completed(SimpleHttpResponse response2) {
            latch1.countDown();
            System.out.println(request2.getRequestUri() + "->" + response2.getCode());
        }

        @Override
        public void failed(Exception ex) {
            latch1.countDown();
            System.out.println(request2.getRequestUri() + "->" + ex);
        }

        @Override
        public void cancelled() {
            latch1.countDown();
            System.out.println(request2.getRequestUri() + " cancelled");
        }

    });

    latch1.await();

    // In real world one most likely would want also want to stream
    // request and response body content
    CountDownLatch latch2 = new CountDownLatch(1);

    AsyncRequestProducer producer3 = AsyncRequestBuilder.get("http://httpbin.org/get").build();

    AbstractCharResponseConsumer<HttpResponse> consumer3 = new AbstractCharResponseConsumer<HttpResponse>() {

        HttpResponse response;

        @Override
        protected void start(HttpResponse response, ContentType contentType) throws HttpException, IOException {
            this.response = response;
        }

        @Override
        protected int capacityIncrement() {
            return Integer.MAX_VALUE;
        }

        @Override
        protected void data(CharBuffer data, boolean endOfStream) throws IOException {
            // Do something useful
        }

        @Override
        protected HttpResponse buildResult() throws IOException {
            return response;
        }

        @Override
        public void releaseResources() {
        }

    };
    httpclient.execute(producer3, consumer3, new FutureCallback<HttpResponse>() {

        @Override
        public void completed(HttpResponse response3) {
            latch2.countDown();
            System.out.println(request2.getRequestUri() + "->" + response3.getCode());
        }

        @Override
        public void failed(Exception ex) {
            latch2.countDown();
            System.out.println(request2.getRequestUri() + "->" + ex);
        }

        @Override
        public void cancelled() {
            latch2.countDown();
            System.out.println(request2.getRequestUri() + " cancelled");
        }

    });

    latch2.await();

}
相关推荐
帅逼码农28 分钟前
Apache Spark
大数据·spark·apache
岳哥说跨境2 小时前
TikTok无网络黑屏原因及解决方法
网络·tcp/ip·http·ip
model20052 小时前
CentOS7 Apache安装踩坑
centos·apache
huahailing10242 小时前
apache-dubbo
apache·dubbo
m0_748247808 小时前
如何使用Node.js快速创建本地HTTP服务器并实现异地远程访问
服务器·http·node.js
搬砖的果果10 小时前
数据采集,如何选择适合自己的HTTP代理?
网络·网络协议·http
davidson147110 小时前
http网络服务-swift-Alamofire
网络协议·http·swift
乌南竹11 小时前
四十五:HTTP/2特性概述
网络·网络协议·http
mikey棒棒棒21 小时前
Apache Echarts和POI
apache·echarts·poi
写bug的小屁孩21 小时前
用户信息界面删除好友功能
运维·服务器·c语言·c++·qt·websocket·http