原文:JEP 321: HTTP Client API

摘要

在 JDK 10 中标准化在 JDK 9 中通过 JEP 110 孵化的 HTTP Client API。

目标

在 JEP 110 的目标之上,还将:

  • 将在孵化版 API 中收到的反馈纳入考虑;
  • 基于孵化版 API,在 java.net.http 包中提供标准 API;
  • 移除孵化版 API。

动机

和 JEP 110 的动机一致。

描述

本提案目标在于标准化在 JDK9 中引入的孵化版 HTTP Client API,并对 JDK10 中的版本进行更新。孵化版 API 收到了很多反馈,并据此进行了重大的改进,但顶层绝大部分保持原样。通过 CompletableFutures 提供了非阻塞的请求、响应语义,以便被串联起来触发后续依赖它的动作。请求体和响应体的背压、流控通过平台的响应式流进行支持 —— 在 java.util.concurrent.Flow API 中。

虽然在 JDK9、JDK10 中进行了孵化,但实现几乎全部重写了。现在的实现是完全异步的(基于 HTTP/1.1 的上一版是阻塞式的)。RX 流概念已经被整合进实现中,终结了很多为支持 HTTP/2 而引入的定制概念。现在可以更容易地追踪数据流,从用户层的请求发送者到响应的订阅者直至底层的套接字。这大大减少了代码中概念的数量和复杂度,最大化了在 HTTP/1.1 和 HTTP/2 之间进行复用的可能。

标准化后的 API 的模块名和包名为 java.net.http。

相比 JDK10 中孵化版 API 的变化

  1. BodyPublisher、BodyHandler、BodySubscriber 的预定义实现——通过静态工厂方法创建,已经被移到隔离的不可实例化工具工厂类中,并按复数命名约定进行命名。提高了这些关联小接口的可读性。
  2. 静态工厂方法名称也进行了更新,命名遵循了以下粗粒度策略
    • fromXxx:来自标准 Subscriber 的适配器,如传入一个 Flow.Subscriber,返回一个 BodySubscriber。
    • ofXxx:创建预定义体 [ Publisher 或 Handler 或 Subscriber ] 的工厂类,这些预定义体执行一些公共任务,如把响应体转换为 String 或流式写入文件。
    • other:组合器(输入一个 BodySubscriber,返回一个 BodySubscriber)或者其他有用工作。
  3. 添加了一些 BodyHandlers 和对应的 BodySubscribers ,提升了一些公共场景的可用性:
    • discard(Object replacement) 组合了忽略响应体和使用给定内容替换的能力。反馈表明这样会引起误解。该方法已经被移除,代之以 2 个独立的 handler:1)discarding() 和 2)replacing(Object replacement)。
    • 添加 ofLines() 方法,该方法返回一个 BodyHandler<Stream<String>>,以支持将流式响应转为一个行流——一行一行的流。提供和 BufferedReader.lines() 类似的语义。
    • 添加 fromLineSubscriber 方法,支持适配将响应体转为基于行流的一个 Flow.Subscriber。
    • 添加 BodySubscriber.mapping 用于从一种响应体格式映射到另一种格式的通用用途。
  4. push 原语被重新支持,以减少对 API 的影响,更符合通常的请求/响应。特别是,MultiSubscriber 和 MultiResultMap 都被移除了。目前在函数式接口中处理 push 原语。在发送动作过程中,可以选择给出一个 PushPromiseHandler。
  5. HttpClient.Redirect 的策略被简化了,使用 NORMAL 替换了 SAME_PROTOCOL 和 SECURE 策略。可以看到之前命名为 SECURE 并不贴合,应重新命名为 NORMAL,更适用于未来大部分正常场景。既然使用了前文的新名字 NORMAL,SAME_PROTOCOL 就显得奇怪了,容易误解,不太可能继续使用。
  6. WebSocket.MessagePart 已被移除。这个枚举值用于接收端标识消息是否发送完毕。发送端使用了一个简单的 boolean 来标识,和接收端的标识方式不对称。可以看到使用一个简单的 boolean 来处理接收到的消息,极大减少了和简化了接收逻辑。判断消息是否已被作为一个整体发送,是上述 MessagePart 的好处之一和主要目的,但已被证明是得不偿失。

关于 API 的更多定义可以查看 JEP 110、最新的 API javadoc、或者网络工作小组的 JDK HTTP Client 页面。

测试

存量的测试用例都是针对孵化版 API 的,将按照新的标准 API 进行更新。同时增加测试用例以覆盖所有支持的场景,特别是 HTTP/1.1 和 HTTP/2 之间的协议升降。

风险和假设

当前依赖了孵化版 HTTP Client API 的代码需要更新,变更引用包的最小化修改。和孵化其他特性的处理方式一样。如果依赖了孵化版模块,会在编译和运行时收到合适的告警。

分类: 扯淡

0 条评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注