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();

}
相关推荐
不可能的是8 小时前
前端 SSE 流式请求三种实现方案全解析
前端·http
古译汉书4 天前
【IoT死磕系列】Day 7:只传8字节怎么控机械臂?学习工业控制 CANopen 的“对象字典”(附企业级源码)
数据结构·stm32·物联网·http
james的分享4 天前
大数据领域核心 SQL 优化框架Apache Calcite介绍
大数据·sql·apache·calcite
莫寒清4 天前
Apache Tika
java·人工智能·spring·apache·知识图谱
归叶再无青4 天前
web服务安装部署、性能升级等(Apache、Nginx)
运维·前端·nginx·云原生·apache·bash
21号 14 天前
Http粘包问题回顾
网络·网络协议·http
A懿轩A4 天前
【SpringBoot 快速开发】面向后端开发的 HTTP 协议详解:请求报文、响应码与常见设计规范
spring boot·http·设计规范
吧啦蹦吧4 天前
http-SNI
网络·网络协议·http
~kiss~5 天前
HTTP 429
网络·网络协议·http
忙碌5445 天前
OpenTelemetry实战指南:构建云原生全链路可观测性体系
ios·flink·apache·iphone