
关于做事,罗斯福的观点修正了我的一个观念,做错好过不做,因为可以从错误中获得真实的反馈,拉进和做对的距离。这样的话,就要重新理解失败,重新理解我这小农经济出身的整套思想观念。
和做事一样,学习陷入过一个误区,知识是一张浩如烟海的相互关联的网,必须要决断在某个点停止继续搜寻信息和准备,在信息不完整的情况下开始实施,否则永远无法开始。
- 译 | JEP 517: HTTP/3 for the HTTP Client API
- 译 | JEP 321: HTTP Client API
- 译 | JEP 110: HTTP/2 Client (Incubator) 👈 bro, you are here
原文:JEP 110: HTTP/2 Client (Incubator)
摘要
定义一个新的、实现了 HTTP/2 和 WebSocket 的 HTTP Client API,并替换掉旧的 HttpURLConnection API。新的 API 将按照 JEP 11 定义的孵化模块方式,在 JDK 9 中发布。这意味着:
- 新 API 及其实现不作为 Java SE 的一部分。
- 新 API 将在 jdk.incubtor 命名空间下才有效。
- 孵化版模块默认在编译或运行时不解析。
动机
现有的 HttpURLConnection API 及其实现有很多问题:
- 基础的 URLConnection API 设计时考虑了多种协议,几乎所有都被废弃了(如 ftp、gopher 等)。
- 早于 HTTP/1.1 存在,过于抽象。
- 难用,有很多行为未记录到文档。
- 只能工作在阻塞模式(如一个线程处理一个请求/响应)。
- 难以维护。
目标
- 必须在常用场景下易用,包括简单的阻塞模式。
- 必须提供事件通知,比如“收到头部”、错误、“收到响应体”。这个通知不必基于回调,但需要能使用像 CompletableFuture 这样的异步机制。
- 一个简单、准确的 API 能应对 80%~90% 的应用需要。这意味着相对小的 API 签名,不会暴露协议的所有能力。
- 必须暴露 HTTP 协议关于从到服务器的请求和从服务器返回的响应的相关内容(如 头部、体、状态码 等)。
- 必须支持标准和通用的认证机制。初始仅限于 Basic 认证方式。
- 必须能方便开启 WebSocket 握手。
- 必须支持 HTTP/2。(HTTP/2 的应用层语义和 HTTP/1.1 基本一致,虽然链路层协议完全不同)
- 必须支持协商从 HTTP/1.1 升级到 HTTP/2(或不能),或者一开始就建立 HTTP/2 连接。
- 必须支持 server push 机制,即 服务端可以在没有接到客户端显式请求的情况下主动向客户端推送资源。
- 必须和现有的网络 API 执行的安全检查保持一致。
- 应对新的语言特性友好,如 lambda 表达式。
- 应对嵌入式系统需求友好,特别是要规避常驻运行的计时器线程。
- 必须支持 HTTPS/TLS。
- HTTP/1.1 的性能要求:
- 性能必须和现有 HttpURLConnection 实现的性能相当。
- 性能必须和 Apache HttpClient 库、当 Netty 或 Jetty 被当做客户端 API 使用时的性能相当。
- 新 API 的内存消耗必须低于或者相当于 HttpURLConnection、Apache HttpClient 库、Netty 或 Jetty 被当做客户端 API 使用时的内存占用情况。
- HTTP/2 的性能要求:
- 性能必须优于 HTTP/1.1(如可扩展性和延迟),在新协议适用的场景里,不管任何系统限制(如 TCP 段 ack 窗口)。
- 性能必须相当于 Netty 或 Jetty 被当做 HTTP/2 的客户端 API 使用时。
- 新 API 的内存消耗必须低于或者相当于 HttpURLConnection、Apache HttpClient 库、Netty 或 Jetty 被当做客户端 API 使用时的内存占用情况。
- 性能比较将只在可比较操作模式的场景中,因为新 API 强调的是在所有可能场景中的简单性和易用性。
- 这些工作是为 JDK 9 准备的。一些代码将被 java EE 复用到 Servlet 4.0 API 关于 HTTP/2 的实现中,所以只有 JDK 8 的语言特性和(在可能的地方)API 会被用到。
- 期待通过吸收在 JDK 9 中使用该 API 的有益经验,使得未来可以在 Java SE,即 JDK 10 的 java.net 空间下,标准化该 API。当在未来的 JEP 中标准化后,将从孵化模块中去掉该 API。
非目标
新 API 最终会用新代码取代 HttpURLConnection API,但不是立马基于新 API 重新实现旧 API。未来再做。
在本 JEP 基于 JDK 8 的早些时候版本中,考虑了一些需求,但被排除了,以保障 API 尽可能简单:
- 请求/响应过滤,
- 可插拔的连接缓存,及
- 通用的升级机制。
其中的一些需求,如 连接缓存,随着 HTTP/2 逐渐被采用,其重要性将随之降低。
描述
已经为 JDK 9 做了一些原型工作,包括定义了分离开的 HTTP 客户端类、请求类、响应类。使用建造者模式把可变实体从不可变的产品中分离出来。为发送和接收定义了一种异步阻塞模式,基于 java.util.concurrent.CompletableFuture 定义了一种异步模式。
原型构建基于 NIO SocketChannel,其异步行为通过 Selectors 和外部提供的 ExecutorServices 实现。
原型是单独实现的,即没有更改当前栈以保证兼容性,同时允许分阶段实施,不需要一开始就支持所有功能。
原型 API 也包括:
- 分出请求和响应,就像 Servlet 和 HTTP server API;
- 下列事件的异步通知:
- 收到响应头,
- 响应错误,
- 收到响应体,及
- Server push(只存在 HTTP/2 中);
- HTTPS,基于 SSLEngine;
- 代理;
- Cookies;及
- 认证。
API 中有部分需要未来完成,如支持 HTTP/2 的多个响应(server push)和 HTTP/2 配置。原型实现几乎完整支持 HTTP/1.1,但对 HTTP/2 的支持不完整。
HTTP/2 代理将在接下来的变更中实现。
其他选择
存在很多 HTTP client API 及其实现,如 Jetty、Apache HttpClient。从包和类的数量来看,这些实现都很重型,同时未利用上新的语言特性,如 lambda 表达式。
测试
内部 HTTP server 将为回归测试和 TCK 测试提供合适的基础。功能性测试也可以用上,但需要基于真实的 HTTP servers 进行测试。
0 条评论