JEP 321: HTTP 客户端
概述
目标
除了 JEP 110 的目标 之外,本 JEP 还将:
- 考虑对孵化版 API 收到的反馈,
- 在
java.net.http
包中基于孵化版 API 提供一个标准化的 API,并且 - 移除孵化版 API。
动机
此 JEP 的动机与 JEP 110 的动机 保持一致。
描述
这个 JEP 提议将 HTTP 客户端 API 标准化,该 API 最初作为孵化中的 API 在 JDK 9 中引入,并在 JDK 10 中进行了更新。这个孵化中的 API 收到了多轮反馈,从而得到了显著改进,但从高层次来看,它基本上保持不变。该 API 通过 CompletableFuture
提供了非阻塞的请求和响应语义,这些语义可以被链接以触发依赖的操作。请求和响应主体的背压(back-pressure)与流量控制是通过平台在 java.util.concurrent.Flow
API 中的 reactive-streams 支持来实现的。
在 JDK 9 和 JDK 10 中孵化期间,该实现几乎已完全重写。该实现现在是完全异步的(之前的 HTTP/1.1 实现是阻塞的)。RX Flow 概念的使用已深入到实现中,这消除了支持 HTTP/2 所需的许多原有自定义概念。数据流现在可以更轻松地被追踪,从用户级别的请求发布者和响应订阅者一直到底层套接字。这大大减少了代码中的概念数量和复杂性,并最大限度地提高了 HTTP/1.1 和 HTTP/2 之间的复用可能性。
标准 API 的模块名和包名将为 java.net.http
。
与 JDK 10 中孵化的内容相比的变更
-
BodyPublisher
、BodyHandler
和BodySubscriber
的预定义实现通过静态工厂方法创建,现已被移至单独的不可实例化的工具工厂类中,并遵循复数命名约定。这提高了这些相对较小型接口的可读性。 -
静态工厂方法的名称也按照以下广泛类别进行了更新:
-
fromXxx
:从标准 Subscriber 适配而来,例如,接收一个Flow.Subscriber
并返回一个BodySubscriber
。 -
ofXxx
:工厂方法,用于创建新的预定义Body[Publisher|Handler|Subscriber]
,执行一些常用的通用任务,例如将响应体作为 String 处理,或将主体流式传输到 File。 -
其他:组合器(接收一个
BodySubscriber
并返回一个BodySubscriber
)以及其他有用的操作。
- 添加了一些
BodyHandler
和相应的BodySubscriber
,以改进在常见场景中的可用性:
-
discard(Object replacement)
结合了丢弃/忽略响应体并允许给定替换的功能。反馈表明这可能会引起混淆。它已被移除并替换为两个独立的处理器:1)discarding()
,和 2)replacing(Object replacement)
。 -
新增了
ofLines()
,它返回一个BodyHandler<Stream<String>>
,以支持将响应体作为一行一行的Stream
流式传输。提供与BufferedReader.lines()
类似的语义。 -
新增了
fromLineSubscriber
,支持将响应体适配为String
行的Flow.Subscriber
。 -
新增了
BodySubscriber.mapping
,用于在不同响应体类型之间进行通用映射。
-
对推送承诺的支持进行了重新设计,以减少其对 API 的影响,并使其更符合常规的请求/响应模式。具体来说,
MultiSubscriber
和MultiResultMap
已被移除。推送承诺现在通过一个函数式接口PushPromiseHandler
来处理,该接口在发送操作期间可选择性提供。 -
通过用
NORMAL
替换SAME_PROTOCOL
和SECURE
策略,简化了HttpClient.Redirect
策略。可以观察到,之前名为SECURE
的策略命名并不恰当,应更名为NORMAL
,因为它很可能适用于大多数常规情况。鉴于上述新命名的NORMAL
,SAME_PROTOCOL
的命名显得怪异,可能引起混淆,并且不太可能被使用。 -
WebSocket.MessagePart
已被移除。此枚举用于接收端,以指示消息的传递是否完成。它与发送端不对称,发送端为此目的使用了一个简单的布尔值。此外,可以观察到,使用简单的布尔值来处理接收到的消息显著减少了并简化了接收代码逻辑。确定消息作为整体 (WHOLE
) 传递(上述MessagePart
的主要优点和主要目的之一)被证明并未发挥出应有的作用。
关于 API 的更多详细信息,请参阅 JEP 110、最新的 API javadoc,或者网络组的 JDK HTTP Client 页面。
测试
现有的针对孵化中的 API 的测试将被更新为使用新的标准 API。将添加额外的测试来覆盖所有支持的场景,特别是 HTTP/1.1 和 HTTP/2 之间的升级和降级。
风险与假设
当前依赖于孵化中的 HTTP Client API 的代码将需要更新,至少要更改其包导入。这与任何其他处于孵化阶段的功能并无不同。依赖于孵化模块的代码在编译时和运行时已经会收到适当的警告。