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 设计时考虑了多种协议,其中几乎所有协议现在都已废弃(如ftp
、gopher
等)。 - 该 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 和实现,例如 Jetty 和 Apache HttpClient 。这两者在包和类的数量上都相当庞大,并且它们没有利用新的语言特性,如 Lambda 表达式。
测试
内部 HTTP 服务器将为回归和 TCK 测试提供适当的基础。功能测试也可以使用它,但可能需要针对实际的 HTTP 服务器进行测试。