如何重现 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 仪器测试 运行,请使用类似的测试。

https://github.com/square/okhttp/blob/master/regression-test/src/androidTest/java/okhttp/regression/compare/OkHttpClientTest.java

@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,需要现有的外部工具。

在您自己的代码中 运行 的步骤

  1. 在你的主要方法中WireSharkListenerFactory.register()
  2. 创建监听器工厂val eventListenerFactory = WireSharkListenerFactory( logFile = File("/tmp/key.log"), tlsVersions = tlsVersions, launch = launch)
  3. 注册client.eventListenerFactory(eventListenerFactory)
  4. 如果没有在外部完成则启动 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://medium.com/@ievgeniitkachenko/different-ways-to-debug-https-requests-in-an-android-emulator-cbf4e0c8ce17

https://hackupstate.medium.com/using-charles-proxy-to-debug-android-ssl-traffic-e61fc38760f7