如何重现 OkHttp 的错误
How to make a reproduction of a bug for OkHttp
我需要用 OkHttp 重现错误,这样我就可以提交错误或在 Whosebug 上提问。
无需大量设置即可完成此操作的最简单方法是什么?
我已经阅读 https://whosebug.com/help/how-to-ask and https://whosebug.com/help/minimal-reproducible-example 但我仍然卡住了?帮帮我!
在 Intellij 中制作一个 Kotlin 脚本,将其放在任何源文件夹之外,并确保它以 .main.kts
文件名结尾。
example.main.kts
#!/usr/bin/env kotlin
@file:Repository("https://repo1.maven.org/maven2/")
@file:DependsOn("com.squareup.okhttp3:okhttp:4.9.0")
@file:CompilerOptions("-jvm-target", "1.8")
import okhttp3.OkHttpClient
import okhttp3.Request
val client = OkHttpClient()
val request = Request.Builder()
.url("https://raw.github.com/square/okhttp/master/README.md")
.build()
val body = client.newCall(request).execute().use {
it.body!!.string()
}
println(body)
#!行意味着它将 运行 像 shell 脚本一样
$ ./example.main.kts
OkHttp
======
See the [project website][okhttp] for documentation and APIs.
...
如果您需要查看事件(连接、请求、响应、缓存),请使用 EventListener。
https://square.github.io/okhttp/events/
在Gradle中添加对com.squareup.okhttp3:logging-interceptor:4.9.1
的依赖
val client = OkHttpClient.Builder()
.eventListenerFactory(LoggingEventListener.Factory())
.build()
[0 ms] callStart: Request{method=GET, url=https://httpbin.org/get}
[11 ms] proxySelectStart: https://httpbin.org/
[12 ms] proxySelectEnd: [DIRECT]
[12 ms] dnsStart: httpbin.org
[55 ms] dnsEnd: [httpbin.org/54.147.165.197, httpbin.org/34.231.30.52, httpbin.org/54.91.118.50, httpbin.org/18.214.80.1, httpbin.org/54.166.163.67, httpbin.org/34.199.75.4]
[62 ms] connectStart: httpbin.org/54.147.165.197:443 DIRECT
[176 ms] secureConnectStart
[747 ms] secureConnectEnd: Handshake{tlsVersion=TLS_1_2 cipherSuite=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 peerCertificates=[CN=httpbin.org, CN=Amazon, OU=Server CA 1B, O=Amazon, C=US, CN=Amazon Root CA 1, O=Amazon, C=US] localCertificates=[]}
[765 ms] connectEnd: h2
[767 ms] connectionAcquired: Connection{httpbin.org:443, proxy=DIRECT hostAddress=httpbin.org/54.147.165.197:443 cipherSuite=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 protocol=h2}
[775 ms] requestHeadersStart
[783 ms] requestHeadersEnd
[993 ms] responseHeadersStart
[994 ms] responseHeadersEnd: Response{protocol=h2, code=200, message=, url=https://httpbin.org/get}
[999 ms] responseBodyStart
[999 ms] responseBodyEnd: byteCount=267
[999 ms] connectionReleased
[1000 ms] callEnd
[0 ms] callStart: Request{method=GET, url=https://httpbin.org/get}
[1 ms] connectionAcquired: Connection{httpbin.org:443, proxy=DIRECT hostAddress=httpbin.org/54.147.165.197:443 cipherSuite=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 protocol=h2}
[1 ms] requestHeadersStart
[1 ms] requestHeadersEnd
[98 ms] responseHeadersStart
[99 ms] responseHeadersEnd: Response{protocol=h2, code=200, message=, url=https://httpbin.org/get}
[99 ms] responseBodyStart
[99 ms] responseBodyEnd: byteCount=267
[99 ms] connectionReleased
[99 ms] callEnd
如果需要查看HTTP/2帧https://square.github.io/okhttp/debug_logging/
[2021-02-27 11:49:39] >> CONNECTION 505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
[2021-02-27 11:49:39] >> 0x00000000 6 SETTINGS
[2021-02-27 11:49:39] >> 0x00000000 4 WINDOW_UPDATE
[2021-02-27 11:49:39] << 0x00000000 18 SETTINGS
[2021-02-27 11:49:39] << 0x00000000 4 WINDOW_UPDATE
[2021-02-27 11:49:39] >> 0x00000003 33 HEADERS END_STREAM|END_HEADERS
[2021-02-27 11:49:39] >> 0x00000000 0 SETTINGS ACK
[2021-02-27 11:49:39] << 0x00000000 0 SETTINGS ACK
[2021-02-27 11:49:39] << 0x00000003 113 HEADERS END_HEADERS
[2021-02-27 11:49:39] << 0x00000003 267 DATA
[2021-02-27 11:49:39] << 0x00000003 0 DATA END_STREAM
跟进请求
[2021-02-27 11:49:39] >> 0x00000005 10 HEADERS END_STREAM|END_HEADERS
[2021-02-27 11:49:39] << 0x00000005 113 HEADERS END_HEADERS
[2021-02-27 11:49:39] << 0x00000005 267 DATA
[2021-02-27 11:49:39] << 0x00000005 0 DATA END_STREAM
要在设备或模拟器上创建 Android 仪器测试 运行,请使用类似的测试。
@RunWith(AndroidJUnit4.class)
public class OkHttpClientTest {
@Test public void get() throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://google.com/robots.txt")
.build();
try (Response response = client.newCall(request).execute()) {
assertEquals(200, response.code());
assertEquals(Protocol.HTTP_2, response.protocol());
}
}
}
步骤 运行 https://github.com/square/okhttp/tree/master/regression-test
如果您需要通过 Wireshark 为 JVM 客户端(JSSE 和 TLSv1.2)查看网络流量https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/kt/WiresharkExample.kt
将 WireSharkKeyLoggerListener 复制到您的测试代码以在开发中使用。
这会在 JVM (OpenJDK 11+) 上记录 TLSv1.2,无需任何额外代码。对于 TLSv1.3,需要现有的外部工具。
在您自己的代码中 运行 的步骤
- 在你的主要方法中
WireSharkListenerFactory.register()
- 创建监听器工厂
val eventListenerFactory = WireSharkListenerFactory( logFile = File("/tmp/key.log"), tlsVersions = tlsVersions, launch = launch)
- 注册
client.eventListenerFactory(eventListenerFactory)
- 如果没有在外部完成则启动 wireshark
val process = eventListenerFactory.launchWireShark()
Capturing on 'Wi-Fi: en0'
Frame 20: 110 bytes on wire (880 bits), 110 bytes captured (880 bits) on interface en0, id 0
Ethernet II, Src: Google_fc:86:a2 (28:bd:89:fc:86:a2), Dst: Apple_6b:3b:e5 (f0:18:98:6b:3b:e5)
Internet Protocol Version 4, Src: 104.244.42.130, Dst: 192.168.86.23
Transmission Control Protocol, Src Port: 443, Dst Port: 57669, Seq: 3531, Ack: 383, Len: 44
Transport Layer Security
TLSv1.2 Record Layer: Application Data Protocol: http2
Content Type: Application Data (23)
Version: TLS 1.2 (0x0303)
Length: 39
Encrypted Application Data: cfb509e24e2ca451923820e45c3943fa521e1f3f1a821fe3468c0a7294e1d07c0ab7ab90…
[Application Data Protocol: http2]
HyperText Transfer Protocol 2
Stream: SETTINGS, Stream ID: 0, Length 6
Length: 6
Type: SETTINGS (4)
Flags: 0x00
0000 000. = Unused: 0x00
.... ...0 = ACK: False
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
Settings - Initial Windows size : 65536
Settings Identifier: Initial Windows size (4)
Initial Windows Size: 65536
...
HyperText Transfer Protocol 2
Stream: HEADERS, Stream ID: 3, Length 53, GET /robots.txt?s=tw
Length: 53
Type: HEADERS (1)
Flags: 0x05, End Headers, End Stream
00.0 ..0. = Unused: 0x00
..0. .... = Priority: False
.... 0... = Padded: False
.... .1.. = End Headers: True
.... ...1 = End Stream: True
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0011 = Stream Identifier: 3
[Pad Length: 0]
Header Block Fragment: 82048c62c3c674a174f94ff88813e3418b1d665d3e0c9496c5c87a7f8750839bd9ab7a91…
[Header Length: 166]
[Header Count: 6]
Header: :method: GET
Name Length: 7
...
您需要将 Wireshark 指向您的密钥日志文件
使用 MITM 调试代理,这些为您提供了用户友好的工具来观察流量。
https://hackupstate.medium.com/using-charles-proxy-to-debug-android-ssl-traffic-e61fc38760f7
我需要用 OkHttp 重现错误,这样我就可以提交错误或在 Whosebug 上提问。
无需大量设置即可完成此操作的最简单方法是什么?
我已经阅读 https://whosebug.com/help/how-to-ask and https://whosebug.com/help/minimal-reproducible-example 但我仍然卡住了?帮帮我!
在 Intellij 中制作一个 Kotlin 脚本,将其放在任何源文件夹之外,并确保它以 .main.kts
文件名结尾。
example.main.kts
#!/usr/bin/env kotlin
@file:Repository("https://repo1.maven.org/maven2/")
@file:DependsOn("com.squareup.okhttp3:okhttp:4.9.0")
@file:CompilerOptions("-jvm-target", "1.8")
import okhttp3.OkHttpClient
import okhttp3.Request
val client = OkHttpClient()
val request = Request.Builder()
.url("https://raw.github.com/square/okhttp/master/README.md")
.build()
val body = client.newCall(request).execute().use {
it.body!!.string()
}
println(body)
#!行意味着它将 运行 像 shell 脚本一样
$ ./example.main.kts
OkHttp
======
See the [project website][okhttp] for documentation and APIs.
...
如果您需要查看事件(连接、请求、响应、缓存),请使用 EventListener。
https://square.github.io/okhttp/events/
在Gradle中添加对com.squareup.okhttp3:logging-interceptor:4.9.1
val client = OkHttpClient.Builder()
.eventListenerFactory(LoggingEventListener.Factory())
.build()
[0 ms] callStart: Request{method=GET, url=https://httpbin.org/get}
[11 ms] proxySelectStart: https://httpbin.org/
[12 ms] proxySelectEnd: [DIRECT]
[12 ms] dnsStart: httpbin.org
[55 ms] dnsEnd: [httpbin.org/54.147.165.197, httpbin.org/34.231.30.52, httpbin.org/54.91.118.50, httpbin.org/18.214.80.1, httpbin.org/54.166.163.67, httpbin.org/34.199.75.4]
[62 ms] connectStart: httpbin.org/54.147.165.197:443 DIRECT
[176 ms] secureConnectStart
[747 ms] secureConnectEnd: Handshake{tlsVersion=TLS_1_2 cipherSuite=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 peerCertificates=[CN=httpbin.org, CN=Amazon, OU=Server CA 1B, O=Amazon, C=US, CN=Amazon Root CA 1, O=Amazon, C=US] localCertificates=[]}
[765 ms] connectEnd: h2
[767 ms] connectionAcquired: Connection{httpbin.org:443, proxy=DIRECT hostAddress=httpbin.org/54.147.165.197:443 cipherSuite=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 protocol=h2}
[775 ms] requestHeadersStart
[783 ms] requestHeadersEnd
[993 ms] responseHeadersStart
[994 ms] responseHeadersEnd: Response{protocol=h2, code=200, message=, url=https://httpbin.org/get}
[999 ms] responseBodyStart
[999 ms] responseBodyEnd: byteCount=267
[999 ms] connectionReleased
[1000 ms] callEnd
[0 ms] callStart: Request{method=GET, url=https://httpbin.org/get}
[1 ms] connectionAcquired: Connection{httpbin.org:443, proxy=DIRECT hostAddress=httpbin.org/54.147.165.197:443 cipherSuite=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 protocol=h2}
[1 ms] requestHeadersStart
[1 ms] requestHeadersEnd
[98 ms] responseHeadersStart
[99 ms] responseHeadersEnd: Response{protocol=h2, code=200, message=, url=https://httpbin.org/get}
[99 ms] responseBodyStart
[99 ms] responseBodyEnd: byteCount=267
[99 ms] connectionReleased
[99 ms] callEnd
如果需要查看HTTP/2帧https://square.github.io/okhttp/debug_logging/
[2021-02-27 11:49:39] >> CONNECTION 505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
[2021-02-27 11:49:39] >> 0x00000000 6 SETTINGS
[2021-02-27 11:49:39] >> 0x00000000 4 WINDOW_UPDATE
[2021-02-27 11:49:39] << 0x00000000 18 SETTINGS
[2021-02-27 11:49:39] << 0x00000000 4 WINDOW_UPDATE
[2021-02-27 11:49:39] >> 0x00000003 33 HEADERS END_STREAM|END_HEADERS
[2021-02-27 11:49:39] >> 0x00000000 0 SETTINGS ACK
[2021-02-27 11:49:39] << 0x00000000 0 SETTINGS ACK
[2021-02-27 11:49:39] << 0x00000003 113 HEADERS END_HEADERS
[2021-02-27 11:49:39] << 0x00000003 267 DATA
[2021-02-27 11:49:39] << 0x00000003 0 DATA END_STREAM
跟进请求
[2021-02-27 11:49:39] >> 0x00000005 10 HEADERS END_STREAM|END_HEADERS
[2021-02-27 11:49:39] << 0x00000005 113 HEADERS END_HEADERS
[2021-02-27 11:49:39] << 0x00000005 267 DATA
[2021-02-27 11:49:39] << 0x00000005 0 DATA END_STREAM
要在设备或模拟器上创建 Android 仪器测试 运行,请使用类似的测试。
@RunWith(AndroidJUnit4.class)
public class OkHttpClientTest {
@Test public void get() throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://google.com/robots.txt")
.build();
try (Response response = client.newCall(request).execute()) {
assertEquals(200, response.code());
assertEquals(Protocol.HTTP_2, response.protocol());
}
}
}
步骤 运行 https://github.com/square/okhttp/tree/master/regression-test
如果您需要通过 Wireshark 为 JVM 客户端(JSSE 和 TLSv1.2)查看网络流量https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/kt/WiresharkExample.kt
将 WireSharkKeyLoggerListener 复制到您的测试代码以在开发中使用。
这会在 JVM (OpenJDK 11+) 上记录 TLSv1.2,无需任何额外代码。对于 TLSv1.3,需要现有的外部工具。
在您自己的代码中 运行 的步骤
- 在你的主要方法中
WireSharkListenerFactory.register()
- 创建监听器工厂
val eventListenerFactory = WireSharkListenerFactory( logFile = File("/tmp/key.log"), tlsVersions = tlsVersions, launch = launch)
- 注册
client.eventListenerFactory(eventListenerFactory)
- 如果没有在外部完成则启动 wireshark
val process = eventListenerFactory.launchWireShark()
Capturing on 'Wi-Fi: en0'
Frame 20: 110 bytes on wire (880 bits), 110 bytes captured (880 bits) on interface en0, id 0
Ethernet II, Src: Google_fc:86:a2 (28:bd:89:fc:86:a2), Dst: Apple_6b:3b:e5 (f0:18:98:6b:3b:e5)
Internet Protocol Version 4, Src: 104.244.42.130, Dst: 192.168.86.23
Transmission Control Protocol, Src Port: 443, Dst Port: 57669, Seq: 3531, Ack: 383, Len: 44
Transport Layer Security
TLSv1.2 Record Layer: Application Data Protocol: http2
Content Type: Application Data (23)
Version: TLS 1.2 (0x0303)
Length: 39
Encrypted Application Data: cfb509e24e2ca451923820e45c3943fa521e1f3f1a821fe3468c0a7294e1d07c0ab7ab90…
[Application Data Protocol: http2]
HyperText Transfer Protocol 2
Stream: SETTINGS, Stream ID: 0, Length 6
Length: 6
Type: SETTINGS (4)
Flags: 0x00
0000 000. = Unused: 0x00
.... ...0 = ACK: False
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
Settings - Initial Windows size : 65536
Settings Identifier: Initial Windows size (4)
Initial Windows Size: 65536
...
HyperText Transfer Protocol 2
Stream: HEADERS, Stream ID: 3, Length 53, GET /robots.txt?s=tw
Length: 53
Type: HEADERS (1)
Flags: 0x05, End Headers, End Stream
00.0 ..0. = Unused: 0x00
..0. .... = Priority: False
.... 0... = Padded: False
.... .1.. = End Headers: True
.... ...1 = End Stream: True
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0000 0000 0011 = Stream Identifier: 3
[Pad Length: 0]
Header Block Fragment: 82048c62c3c674a174f94ff88813e3418b1d665d3e0c9496c5c87a7f8750839bd9ab7a91…
[Header Length: 166]
[Header Count: 6]
Header: :method: GET
Name Length: 7
...
您需要将 Wireshark 指向您的密钥日志文件
使用 MITM 调试代理,这些为您提供了用户友好的工具来观察流量。
https://hackupstate.medium.com/using-charles-proxy-to-debug-android-ssl-traffic-e61fc38760f7