Android 11 更新后的 UnknownHostException

问题描述

问题:一旦返回 UnkNownHostException,用户将继续收到相同的错误,除非重新安装应用程序或重新启动设备。

在操作系统为 Android 11 的用户中,只有少数用户遇到问题。

最大的问题是,当出现错误时,每次请求都会不断返回相同的错误

用户称,重新安装应用程序或重新启动设备会再次工作。

似乎 99% 是三星设备的用户。有时还有 Google Pixel 手机。

Http 和 Https 都给出相同的错误

Wifi、5G 和 LTE 都会出现相同的错误

请求方法是使用POST,不知道GET是否也是这样,我没有使用GET。

此外,线程是后台前台,或两者兼而有之。

这是我的代码

Gradle:

android {
    minSdkVersion 21
    
    kotlinoptions {
        jvmTarget = JavaVersion.VERSION_1_8.toString()
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {

    /* RETROFIT */
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'

    /* OKHTTP */
    implementation 'com.squareup.okhttp3:okhttp:4.9.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
    implementation 'com.squareup.okhttp3:okhttp-urlconnection:4.9.0'

    /* RXJAVA RXANDROID */
    implementation 'io.reactivex.rxjava3:rxjava:3.0.11'
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'

}

创建请求:


interface ApiService {

    @POST("get-data")
    fun getData(@Body parameter : CustomParameter): Single<Response<CustomObject>>

    companion object {

        private val rxJava3CallAdapterFactory: RxJava3CallAdapterFactory
            get() = RxJava3CallAdapterFactory.createWithScheduler(Schedulers.io())

        private fun okHttpClient(): OkHttpClient {
            val okHttpClientBuilder = okHttpClientBuilder()

            okHttpClientBuilder.addNetworkInterceptor { chain ->
                val request = chain.request()
                val response = chain.proceed(request)
                if (response.code >= 400) {
                    handleNetworkError()
                }
                response
            }

            okHttpClientBuilder.addInterceptor { chain ->
                val request = chain.request()
                chain.proceed(request)
            }

            return okHttpClientBuilder.build()
        }

        fun createApiService(context: Context): ApiService {
            val retrofit = Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(rxJava3CallAdapterFactory)
                    .client(okHttpClient())
                    .build()

            return retrofit.create(ApiService::class.java)
        }
    }
}

呼叫请求(活动中):

    ApiService.createMainWeatherApiService().getData(CustomParameter())
              .subscribeOn(Schedulers.io())
              .observeOn(AndroidSchedulers.mainThread())
              .subscribe(
                      { res ->
                          handleSuccess()
                      },{ error ->
                          // UnkNownHostException!!!!
                          handleFail()
                      }
              ).apply { compositedisposable.add(this) }

我在 okhttp 上创建了一个问题:https://github.com/square/okhttp/issues/6591

解决方法

您能否包含事件侦听器的输出,该输出将显示 OkHttp(通常)使用系统 DNS 提供程序进行的 DNS 调用?

https://stackoverflow.com/a/66398516/1542667

[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,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

第二个请求可能会跳过这个,见下文,以重用连接。但在您的情况下,您希望它在建立新连接之前发出新的 DNS 请求。

[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,url=https://httpbin.org/get}
[99 ms] responseBodyStart
[99 ms] responseBodyEnd: byteCount=267
[99 ms] connectionReleased
[99 ms] callEnd

如果它显示您在每次调用时都进行查询,那么您很可能会看到相同的行为,只是在程序中多次调用 InetAddress.getAllByName(hostname).toList()。你希望它显示什么?