Skip to content

JEP 110: HTTP/2 Client (Incubator)

摘要

定义一个新的 HTTP 客户端 API,实现 HTTP/2 和 WebSocket,并可以替代传统的HttpURLConnection API。该 API 将作为孵化器模块交付,根据JEP 11在 JDK 9 中定义。这意味着:

  • API 和实现不会成为 Java SE 的一部分。
  • API 将位于 jdk.incubator 命名空间下。
  • 该模块在编译或运行时默认不会被解析。

动机

现有的 HttpURLConnection API 及其实现存在许多问题:

  • 基本的 URLConnection API 设计时考虑了多种协议,其中几乎所有协议现在都已废弃(如 ftpgopher 等)。
  • 该 API 早于 HTTP/1.1,并且过于抽象。
  • 使用起来很困难,有许多未记录的行为。
  • 它只能以阻塞模式工作(即每个请求/响应一个线程)。
  • 很难进行维护。

目标

  • 对于常见情况,必须易于使用,包括简单的阻塞模式。
  • 必须提供事件通知,如“接收到头部”,错误和“接收到响应体”。此通知不一定基于回调,可以使用类似 CompletableFuture 的异步机制。
  • 提供简单而简洁的 API,满足 80-90% 的应用需求。这可能意味着相对较小的 API 规模,不一定公开协议的所有功能。
  • 必须向服务器公开 HTTP 协议请求的所有相关方面,以及来自服务器的响应(头部、正文、状态码等)。
  • 必须支持标准和常见的身份验证机制。最初将仅限于基本身份验证。
  • 必须能够轻松设置 WebSocket 握手。
  • 必须支持HTTP/2。(HTTP/2 的应用级语义与 1.1 大致相同,但传输协议完全不同。)
    • 必须能够从 1.1 升级到 2(或不升级),或者从一开始就选择 2。
    • 必须支持服务器推送,即服务器能够在客户端没有明确请求的情况下向客户端推送资源。
  • 必须执行与现有网络 API 一致的安全检查。
  • 应对新的语言特性(如 Lambda 表达式)友好。
  • 应对嵌入式系统要求友好,特别是避免永久运行计时器线程。
  • 必须支持 HTTPS/TLS。
  • HTTP/1.1 的性能要求:
    • 性能必须与现有的 HttpURLConnection 实现相当。
    • 性能必须与 Apache HttpClient 库以及作为客户端 API 使用的 Netty 和 Jetty 相当。
    • 新 API 的内存消耗必须与 HttpURLConnection、Apache HttpClient 以及作为客户端 API 使用的 Netty 和 Jetty 相当或更低。
  • HTTP/2的性能要求:
    • 性能必须优于 HTTP/1.1,符合新协议预期的方式(如可扩展性和延迟),不考虑任何平台限制(如 TCP 段确认窗口)。
    • 性能必须与作为客户端 API 使用的 Netty 和 Jetty 相当。
    • 新 API 的内存消耗必须与使用 HttpURLConnection、Apache HttpClient 以及作为客户端 API 使用的 Netty 和 Jetty 相当或更低。
  • 性能比较将仅针对可比较的操作模式,因为新 API 强调简单易用,而不是覆盖所有可能的用例,
  • 此工作面向 JDK 9。一些代码可能会在 Java EE 中被重用,用于在 Servlet 4.0 API 中实现 HTTP/2,因此只使用 JDK 8 的语言特性和可能的 API。
  • 借助在 JDK 9 中使用 API 的经验,有望在 JDK 10 中将 API 规范化为 Java SE 的一部分,位于 java.net 命名空间下。当发生这种情况时,作为未来 JEP 的一部分,API 将不再作为孵化器模块存在。

非目标

此 API 旨在最终替代 HttpURLConnection API 用于新代码,但我们不打算立即使用新 API 重新实现旧 API。这可能是未来的工作。

一些要求在此 JEP 的 JDK 8 早期版本中被考虑过,但为了尽可能简化 API,它们被忽略了:

  • 请求/响应过滤,
  • 可插拔的连接缓存,以及
  • 通用升级机制。

其中一些要求,例如连接缓存,将随着 HTTP/2 的逐步采用而变得不那么重要。

描述

在 JDK 9 中进行了一些原型工作,其中为 HTTP 客户端、请求和响应定义了单独的类。使用构建器模式将可变实体与不可变产品分离。定义了同步阻塞模式用于发送和接收,还定义了基于 java.util.concurrent.CompletableFuture 的异步模式。

该原型是基于 NIO SocketChannels 构建的,使用选择器实现了异步行为,并使用外部提供的 ExecutorServices。

原型实现是独立的,即现有堆栈没有更改,以确保兼容性,并允许分阶段的方法,不需要在开始时支持所有功能。

原型 API 还包括:

  • 分离的请求和响应,类似于 Servlet 和 HTTP 服务器 API;
  • 异步通知以下事件:
    • 收到响应头部,
    • 响应错误,
    • 收到响应正文,以及
    • 服务器推送(仅限 HTTP/2);
  • 通过 SSLEngine 支持 HTTPS;
  • 代理;
  • Cookies;和
  • 身份验证。

最有可能需要进一步改进的部分是对 HTTP/2 多响应(服务器推送)和 HTTP/2 配置的支持。原型实现几乎支持所有 HTTP/1.1,但尚未支持 HTTP/2。

HTTP/2代理将在随后的更改中实现。

备选方案

存在许多现有的 HTTP 客户端 API 和实现,例如 JettyApache HttpClient 。这两者在包和类的数量上都相当庞大,并且它们没有利用新的语言特性,如 Lambda 表达式。

测试

内部 HTTP 服务器将为回归和 TCK 测试提供适当的基础。功能测试也可以使用它,但可能需要针对实际的 HTTP 服务器进行测试。