OkHttp 4.x 变更日志¶
版本 4.12.0¶
2023-10-16
-
修复:处理 HTTP 103 响应的头部时不再挂起。
-
修复:当缓存条目的证书损坏时,能优雅地恢复。
-
修复:加载捆绑的公共后缀数据库失败时,永久性地失败。这是为
HttpUrl.topPrivateDomain()
提供支持的数据集。 -
修复:立即更新连接的流量控制窗口,而不是等待接收流处理它。
此更改可能会增加 OkHttp 在并发 HTTP 调用较多且接收数据速度快于处理速度的应用中的内存使用量。以前,OkHttp 将 HTTP/2 的每个连接的未确认数据限制为 16 MiB。此修复后,每个流的未确认数据限制为 16 MiB,但没有每连接限制。
-
修复:连接返回连接池后,不再对其进行操作。此竞态条件发生在失败的 WebSocket 连接尝试中。
-
升级:Okio 3.6.0。
-
升级:Kotlin 1.8.21。
版本 4.11.0¶
2023-04-22
- 修复:当响应码是 ‘HTTP 102 Processing’ 或 ‘HTTP 103 Early Hints’ 时,不导致调用失败。
- 修复:即使写入请求失败,也会读取响应。这意味着即使服务器拒绝了您的请求体,您仍然会收到正确的 HTTP 响应。
- 修复:直接使用字面量 IP 地址,而不是将它们传递给
DnsOverHttps
。 - 修复:嵌入 Proguard 规则以防止 DexGuard 和 R8 等工具发出警告。这些警告是由 OkHttp 对
org.conscrypt
、org.bouncycastle
和org.openjsse
等 TLS 包进行特性检测时触发的。 - 升级:明确依赖
kotlin-stdlib-jdk8
。这修复了依赖锁定中的一个问题。这是一个潜在的安全漏洞,追踪编号为 CVE-2022-24329。 - 升级:publicsuffix.org 数据。这为
HttpUrl.topPrivateDomain()
提供支持。OkHttp 也通过它知道哪些域可以相互共享 cookie。 - 升级:Okio 3.2.0。
版本 4.10.0¶
2022-06-12
- 升级:Kotlin 1.6.20。
- 升级:Okio 3.0.0。
- 修复:当 Android 的
NativeCrypto
崩溃并显示"ssl == null"
时,能优雅地恢复。这发生在 OkHttp 在关闭的连接上检索 ALPN 状态时。
版本 4.9.3¶
2021-11-21
- 修复:如果 HTTP/2 响应在发送
RST_STREAM
之前完成,则不导致失败。
版本 4.9.2¶
2021-09-30
- 修复:不在
Headers.toString()
或异常中包含潜在敏感的头部值。这适用于Authorization
、Cookie
、Proxy-Authorization
和Set-Cookie
头部。 - 修复:在 JDK17+ 上启用强封装时,不会因
InaccessibleObjectException
而崩溃。 - 修复:严格验证与 OkHttp 的
HostnameVerifier
一起使用的主机名。如果传入的主机名不是严格的 ASCII,则直接手动调用HostnameVerifier
的程序可能会被攻破。此问题追踪编号为 CVE-2021-0341。
版本 4.9.1¶
2021-01-30
- 修复:解决 Android 10 和 11 中的一个崩溃问题,该问题可能在两个线程并发关闭 SSL socket 时触发。这在崩溃日志中会显示为
NullPointerException: bio == null
。
版本 4.9.0¶
2020-09-11
从本版本开始,okhttp-tls
不再依赖 Bouncy Castle 并且不安装 Bouncy Castle 安全提供者。 如果您仍然需要它,可以自行完成。
Security.addProvider(BouncyCastleProvider())
您还需要配置此依赖。
dependencies {
implementation "org.bouncycastle:bcprov-jdk15on:1.65"
}
- 升级:Kotlin 1.4.10。我们现在对
Authenticator
、Interceptor
等使用 Kotlin 1.4.x 的函数式接口。 - 升级:使用 Conscrypt 2.5.1 构建。
版本 4.8.1¶
2020-08-06
- 修复:在较旧的 Android 版本(包括 Android 6)上创建证书时,
HeldCertificate.Builder
中不会崩溃。我们使用了一个SimpleDateFormat
的特性,而该特性在这些版本中不可用!
版本 4.8.0¶
2020-07-11
-
新增:更改
HeldCertificate.Builder
以使用自己的 ASN.1 证书编码器。这是我们移除 okhttp-tls 模块对 Bouncy Castle 依赖的一部分努力。我们认为 Bouncy Castle 很棒!但它是一个庞大的依赖(6.5 MiB),并且其安全提供者特性会影响 VM 范围的行为。 -
新增:减少并发请求量非常高的应用中的争用。以前,OkHttp 在修改连接和调用时,会使用连接池作为锁。此更改后,每个连接独立锁定。
-
升级:Okio 2.7.0。
implementation("com.squareup.okio:okio:2.7.0")
-
修复:在检测宿主平台的 TLS 能力时,避免出现“Didn’t find class org.conscrypt.ConscryptHostnameVerifier”之类的日志消息。
-
修复:当主机名格式错误时,
HttpUrl.topPrivateDomain()
中不会崩溃。 -
修复:如果响应体为空,则不尝试进行 Brotli 解压缩。
版本 4.7.2¶
2020-05-20
- 修复:在检查宿主平台是 JVM 还是 Android 时不会崩溃。在 4.7.0 和 4.7.1 版本中,我们由于依赖伴生对象的初始化顺序,曾出现
IllegalArgumentException: Not a Conscrypt trust manager
的崩溃。
版本 4.7.1¶
2020-05-18
- 修复:在为
addInsecureHost()
创建的信任管理器中传递正确的参数。如果没有此修复,不安全的主机将在 Android 上因IllegalArgumentException
而崩溃。
版本 4.7.0¶
2020-05-17
-
新增:
HandshakeCertificates.Builder.addInsecureHost()
使在只包含测试数据的私有开发环境中轻松关闭安全性。优先使用此方法而非创建完全信任的TrustManager
,因为只有允许列表中的主机才是不安全的。来自我们的 DevServer 示例val clientCertificates = HandshakeCertificates.Builder() .addPlatformTrustedCertificates() .addInsecureHost("localhost") .build() val client = OkHttpClient.Builder() .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) .build()
-
新增:向
EventListener
添加cacheHit
、cacheMiss
和cacheConditionalHit()
事件。在日志、指标甚至测试用例中使用这些事件,以确认您的缓存头部已按预期配置。 -
新增:常量字符串
okhttp3.VERSION
。这是一个类似于“4.5.0-RC1”、“4.5.0”或“4.6.0-SNAPSHOT”的字符串,指示当前运行时的 OkHttp 版本。使用此常量可在自定义User-Agent
头部中包含 OkHttp 版本。 -
修复:在 Android Studio Canary 4.1 中作为插件运行时不会崩溃。为了启用特定于平台的 TLS 特性,OkHttp 必须检测它是在 JVM 中运行还是在 Android 中运行。即将发布的 Android Studio 运行在 JVM 中,但包含了 Android 的类,这让 OkHttp 感到困惑!
-
修复:对于 SSE 调用,包含头部
Accept: text/event-stream
。如果请求已包含Accept
头部,则不添加此头部。 -
修复:如果服务器在我们发送 ping 时发送关闭,不会因
NullPointerException
而崩溃。OkHttp 曾存在一个竞态条件 bug。
版本 4.6.0¶
2020-04-28
-
修复:对 GET 和 POST 以外的方法遵循 HTTP 307 和 308 重定向。我们不愿意改变 OkHttp 处理常见 HTTP 状态码的行为,但这个修复早就该做了!新行为现在与RFC 7231(比 OkHttp 本身还新)保持一致。如果您想要此更新但保留旧行为,请使用此拦截器。
-
修复:解压 WebSocket 消息时不会崩溃。我们曾有一个 bug,错误地假设输入的是已压缩字节,输出就总是已压缩字节,而实际并非总是如此!
-
修复:在 Windows 上可靠地更新和失效磁盘缓存。最初设计的内部
DiskLruCache
假设文件系统类似于 inode,可以删除正在读写的文件。在 Windows 上,文件系统禁止这样做,因此在删除和重命名文件时必须更加小心。 -
修复:在 Java 8u252 上不会崩溃,该版本引入了一个以前仅在 Java 9 及更高版本中存在的 API。请参阅Jetty 的概述了解 API 更改及其后果。
-
新增:
MultipartReader
是用于 MIME multipart (RFC 2045) 消息的流式解码器。它补充了我们的流式编码器MultipartBody
。val response: Response = call.execute() val multipartReader = MultipartReader(response.body!!) multipartReader.use { while (true) { val part = multipartReader.nextPart() ?: break process(part.headers, part.body) } }
-
新增:
MediaType.parameter()
从multipart/mixed; boundary="abc"
这样的媒体类型中获取像boundary
这样的参数。 -
新增:
Authenticator.JAVA_NET_AUTHENTICATOR
将身份验证请求转发到java.net.Authenticator
。这使得 okhttp-urlconnection 模块中的JavaNetAuthenticator
过时。 -
新增:
CertificatePinner
现在提供用于检查配置的 pinning 的 API。 -
升级:Okio 2.6.0。
implementation("com.squareup.okio:okio:2.6.0")
-
升级:publicsuffix.org 数据。这为
HttpUrl.topPrivateDomain()
提供支持。OkHttp 也通过它知道哪些域可以相互共享 cookie。 -
升级:Bouncy Castle 1.65。okhttp-tls 模块需要此依赖。
-
升级:Kotlin 1.3.71。
版本 4.5.0¶
2020-04-06
此版本修复了一个严重错误,其中 OkHttp 错误地检测并从不健康的连接中恢复。 已失效或已取消的连接被错误地尝试使用,本不该如此,这导致了罕见的无限重试情况。请升级到此版本!
- 修复:不在
DnsOverHttps
中返回陈旧的 DNS 条目。我们之前无限期地缓存 DNS 结果,而不是按照响应的 cache-control 头部指定的持续时间。 - 修复:以规范形式验证证书 IP 地址。当服务器提供包含 IP 地址的 TLS 证书时,即使两个地址编码不同(例如
192.168.1.1
和0::0:0:FFFF:C0A8:101
),我们也必须将该地址与 URL 的 IP 地址进行匹配。请注意,OkHttp 曾错误地拒绝了有效证书,导致连接失败;但从未接受过无效证书。 - 新增:
OkHttpClient.Builder.minWebSocketMessageToCompress()
配置了压缩出站 WebSocket 消息的阈值。将其配置为0L
表示总是压缩出站消息,配置为Long.MAX_VALUE
表示从不压缩出站消息。默认值为1024L
,表示压缩大小为 1 KiB 及更大的消息。(入站消息是否压缩取决于 WebSocket 服务器的配置。) - 新增:延迟构造
Inflater
和Deflater
实例直到需要时再进行。如果协商了 WebSocket 压缩但未实际使用,这可以节省内存。
版本 4.5.0-RC1¶
2020-03-17
此候选版本开启了 WebSocket 压缩。
此规范包含了一个复杂的机制,供客户端和服务器协商压缩特性。我们致力于在默认配置下提供卓越的性能,因此从这个候选版本开始,我们将压缩作为所有用户的默认设置。
在推广此版本时,请考虑您的服务器及其运维人员。压缩可以节省带宽,但会消耗 CPU 和内存!如果遇到问题,您可能需要在服务器上调整或禁用 permessage-deflate
压缩设置。
请注意,发送小于 1 KiB 的消息时,OkHttp 不会使用压缩。
- 修复:当 URL 主机名在 Android 上包含下划线时不会崩溃。
- 修复:更改 HTTP/2 以使用守护线程作为其 socket 读取器。如果您曾见过命令行应用在完成所有工作后挂起,可能是由于像这样的非守护线程。
- 新增:当到目标服务的所有路由都失败时,包含被抑制的异常。
版本 4.4.1¶
2020-03-08
-
修复:如果证书匹配但 DNS 不匹配,重定向时不要重用连接。为了更好的本地性和性能,OkHttp 尝试在重定向和后续请求中重用同一池化连接。当 IP 地址和证书匹配时,即使主机名不匹配,它也会独立共享连接。在 4.4.0 版本中,我们引入了一个回归问题,即当证书匹配但 DNS 地址不匹配时,我们共享了连接。这只会发生在从一个主机名重定向到另一个主机名,并且两个主机都有共同证书的情况下。
-
修复:当客户端配置了“信任所有”信任管理器时,重定向不会失败。通常,这会导致某些重定向在调试和开发配置中失败。
版本 4.4.0¶
2020-02-17
-
新增:支持
canceled()
作为EventListener
可观察到的事件。这对于在指标中区分已取消的调用应该很有用。 -
新增:发布 OkHttp 的物料清单 (BOM)。通过 Gradle 或 Maven 依赖此 BOM,以使所有 OkHttp 构件保持同一版本,即使它们是通过传递依赖声明的。在声明其他 OkHttp 依赖时,甚至可以省略版本。
dependencies { api(platform("com.squareup.okhttp3:okhttp-bom:4.4.0")) api("com.squareup.okhttp3:okhttp") // No version! api("com.squareup.okhttp3:logging-interceptor") // No version! }
-
新增:升级到 Okio 2.4.3。
implementation("com.squareup.okio:okio:2.4.3")
-
修复:限制 HTTP/2
REFUSED_STREAM
和CANCEL
失败的重试次数。 - 修复:当在多个主机名之间错误地共享连接时自动重试。当主机共享 IP 地址和证书时(例如 squareup.com 和 www.squareup.com),OkHttp 会共享连接。如果服务器拒绝此类共享,它将返回 HTTP 421,并且 OkHttp 将在未共享的连接上自动重试。
- 修复:如果 TLS 隧道响应体被截断,不会崩溃。
- 修复:不再跟踪无用的路由。我们曾有一个 bug,可以无限期地跟踪某些坏路由;现在我们只跟踪那些可能需要的路由。
- 修复:延迟代理选择直到需要代理。这在使用池化连接的调用中,节省了对
ProxySelector
的调用。
版本 4.3.1¶
2020-01-07
- 修复:当 WebSocket 在连接之前关闭时,不会因
NullPointerException
而崩溃。这是 OkHttp 4.3.0 中引入的一个回归问题。 - 修复:在 Android 10 上使用自定义信任管理器时,不会因
IllegalArgumentException
而崩溃。Android 使用反射查找一个神奇的checkServerTrusted()
方法,而我们没有实现它。 - 修复:在 Android 5 上进行 HTTPS 连接时,明确指定远程服务器名称。在 4.3.0 版本中,我们引入了一个回归问题,导致 Android 5 上的服务器名称指示 (SNI) 失效。
版本 4.3.0¶
2019-12-31
-
修复:超时后降级 HTTP/2 连接。当 HTTP/2 流超时时,可能只影响该流或整个连接。通过此修复,OkHttp 现在会在流超时后发送 HTTP/2 ping 以确定连接是否应继续符合池化条件。
-
修复:在收到字节之前,不调用
EventListener.responseHeadersStart()
或responseBodyStart()
。之前这些事件错误地发送得太早,即 OkHttp 准备读取响应头部或响应体时,这误导了跟踪工具。请注意,responseFailed()
事件过去总是紧随这些事件之一;现在它可以在没有这些事件的情况下发送。 -
新增:升级到 Kotlin 1.3.61。
-
新增:在
CertificatePinner
中使用两个星号匹配任意数量的子域。例如,**.squareup.com
匹配us-west.www.squareup.com
、www.squareup.com
和squareup.com
。 -
新增:在 OkHttp 的 HTTP/2 连接、连接池、WebSocket 和缓存之间更积极地共享线程。OkHttp 有一个新的内部任务运行器抽象,用于管理任务调度。在您的调试器中,您将看到新的线程名称和更多地使用守护线程。
-
修复:遇到意外异常时,不丢弃回调。当拦截器抛出未经检查的异常时,回调现在会被通知调用已取消。该异常仍然发送给未捕获异常处理器以进行报告和恢复。
-
修复:取消弃用
MockResponse.setHeaders()
和其他 setter 方法。这些方法在 OkHttp 4.0 中被弃用,但破坏了 Java 调用者的链式调用。 -
修复:在 HTTP/2 HEAD 请求中,如果
Content-Length
头部存在但与响应体的长度不一致,不会崩溃。 -
修复:将具有无法解析主机名的
HttpUrl
实例转换为 URI 时,不会崩溃。新行为会在转换前,从主机名中去除诸如"
和{
等无效字符。 -
修复:撤销 OkHttp 4.0 中引入的性能回归,该回归是由 Kotlin 的
assert()
和 Java 的assert()
行为差异引起的。(Kotlin 总是评估参数;Java 只在启用断言时评估。) -
修复:在
HttpLoggingInterceptor
中遵守RequestBody.isOneShot()
。
版本 4.2.2¶
2019-10-06
- 修复:在关闭已取消的 HTTP/2 流时,不发送
END_STREAM
标志。这可能导致服务器错误地将该流解释为正常完成。这在请求体需要取消自身调用时最有用。
版本 4.2.1¶
2019-10-02
-
修复:在 4.1.0 版本中,我们引入了一个性能回归问题,导致在某些情况下连接无法被池化。我们对连接池有良好的测试覆盖率,但我们遗漏了这个问题,因为它只发生在配置了代理且在多个 OkHttpClient 实例之间共享连接池的情况下。
这个特别微妙的 bug 是由于当配置了显式代理时,我们为每个 OkHttpClient 实例分配了其自己的 NullProxySelector 引起的。但当代理选择器不同时,我们不会共享连接。哎!
版本 4.2.0¶
2019-09-10
-
新增:解码证书和私钥以创建
HeldCertificate
的 API。此 API 接受一个包含证书和 PKCS #8 编码的私钥的字符串。val heldCertificate = HeldCertificate.decode(""" |-----BEGIN CERTIFICATE----- |MIIBYTCCAQegAwIBAgIBKjAKBggqhkjOPQQDAjApMRQwEgYDVQQLEwtlbmdpbmVl |cmluZzERMA8GA1UEAxMIY2FzaC5hcHAwHhcNNzAwMTAxMDAwMDA1WhcNNzAwMTAx |MDAwMDEwWjApMRQwEgYDVQQLEwtlbmdpbmVlcmluZzERMA8GA1UEAxMIY2FzaC5h |cHAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASda8ChkQXxGELnrV/oBnIAx3dD |ocUOJfdz4pOJTP6dVQB9U3UBiW5uSX/MoOD0LL5zG3bVyL3Y6pDwKuYvfLNhoyAw |HjAcBgNVHREBAf8EEjAQhwQBAQEBgghjYXNoLmFwcDAKBggqhkjOPQQDAgNIADBF |AiAyHHg1N6YDDQiY920+cnI5XSZwEGhAtb9PYWO8bLmkcQIhAI2CfEZf3V/obmdT |yyaoEufLKVXhrTQhRfodTeigi4RX |-----END CERTIFICATE----- |-----BEGIN PRIVATE KEY----- |MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCA7ODT0xhGSNn4ESj6J |lu/GJQZoU9lDrCPeUcQ28tzOWw== |-----END PRIVATE KEY----- """.trimMargin()) val handshakeCertificates = HandshakeCertificates.Builder() .heldCertificate(heldCertificate) .build() val server = MockWebServer() server.useHttps(handshakeCertificates.sslSocketFactory(), false)
使用
HeldCertificate.certificatePem()
和privateKeyPkcs8Pem()
获取这些字符串。 -
修复:握手现在按规范顺序返回对端证书:每个证书由其后续证书签名,最后一个证书由信任根签名。
-
修复:当接收数据与流关闭发生竞态时,不会丢失 HTTP/2 流量控制字节。如果这种情况发生足够多次,连接最终会停滞。
-
修复:原子地确认并应用入站 HTTP/2 设置。之前我们有一个竞态问题,即在确认新的流量控制容量之前就可以使用它,导致严格的 HTTP/2 服务器使调用失败。
版本 4.1.1¶
2019-09-05
- 修复:验证缓存响应时,不丢弃重复的头部。在我们的 Kotlin 升级中,我们引入了一个回归问题,即我们迭代的是唯一头部名称的数量,而不是唯一头部的数量。如果您使用 OkHttp 的响应缓存,这可能会影响您。
版本 4.1.0¶
2019-08-12
-
OkHttp 新的 okhttp-brotli 模块实现了 Brotli 压缩。 安装该拦截器以启用Brotli 压缩,其压缩率比 gzip 小 5-20%。
val client = OkHttpClient.Builder() .addInterceptor(BrotliInterceptor) .build()
此构件依赖于 Google 的 Brotli 解码器(95 KiB)。
-
新增:
EventListener.proxySelectStart()
,proxySelectEnd()
事件提供了对代理选择过程的可见性。 - 新增:
Response.byteString()
将整个响应作为字节字符串读入内存。 - 新增:
OkHttpClient.x509TrustManager
访问器。 - 新增:允许新的 WebSocket 响应码:1012 (服务重启),1013 (稍后重试),以及 1014 (来自上游的无效响应)。
- 新增:使用 Kotlin 1.3.41, BouncyCastle 1.62, 和 Conscrypt 2.2.1 构建。
- 修复:当合并的连接立即变得不健康时,能优雅地恢复。
- 修复:查找默认代理选择器时,延迟抛出
SecurityException
。 - 修复:在 MockWebServer 中,IPv6 主机名不使用方括号格式化。
- 修复:不允许缓存迭代器移除正在写入的条目。
版本 4.0.1¶
2019-07-10
- 修复:在公共 API 中容忍对 null 不友好的列表。使用
List.of(...)
创建的列表不喜欢您对其调用contains(null)
! - 修复:在
okhttp3.internal.HttpHeaders.hasBody()
中保留二进制兼容性。有些不择手段的编码者会调用此方法,我们不希望他们的用户因此受苦。
版本 4.0.0¶
2019-06-26
此版本将 OkHttp 升级到 Kotlin。 我们尽力使从 OkHttp 3.x 升级快速且安全。我们编写了升级指南以帮助迁移,并撰写了博文进行解释。
- 修复:Java 和 Kotlin 目标字节码为 Java 8。
版本 4.0.0-RC3¶
2019-06-24
- 修复:在
okhttp3.internal.HttpMethod
中保留二进制兼容性。不良的第三方 SDK 会导入此方法,我们希望方便其用户进行升级。
版本 4.0.0-RC2¶
2019-06-21
- 新增:要求 Kotlin 1.3.40。
- 新增:将 Kotlin API 从
File.toRequestBody()
更改为File.asRequestBody()
,并将BufferedSource.toResponseBody()
更改为BufferedSource.asResponseBody()
。如果返回的值是创建它的视图,则使用 *as*。 - 修复:允许响应码为零,以与 OkHttp 3.x 兼容。
- 修复:将
MockWebServer.takeRequest()
的返回类型更改为可空。 - 修复:使
Call.clone()
对 Kotlin 调用者公开。
版本 4.0.0-RC1¶
2019-06-03
- OkHttp 4 的第一个稳定预览版。