【问题标题】:HttpURLConnection in Android working fine, but OkHttp gives "Network is unreachable" on KitkatAndroid 中的 HttpURLConnection 工作正常,但 OkHttp 在 Kitkat 上给出“网络无法访问”
【发布时间】:2026-01-23 10:40:01
【问题描述】:

我对这个特定网站有疑问:https://tastedive.com/read/api

如果我使用 HttpURLConnection 进行 HTTP 请求,我会得到正常的 HTML 响应(在 Android 上,此代码需要位于单独的线程中,并且还需要放置所有必要的尝试和捕获):

    StringBuilder result = new StringBuilder();
    URL url = new URL("https://tastedive.com/read/api");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("GET");
    BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String line;
    while ((line = rd.readLine()) != null) {
        result.append(line);
    }
    rd.close();
    System.out.println(result.toString());  // shows normal HTML response

但如果我用 OkHttp 来做,用这段代码......

    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder()
            .url("https://tastedive.com/read/api")
            .build();
    client.newCall(request).enqueue(new okhttp3.Callback() {
        @Override
        public void onFailure(okhttp3.Call call, IOException e) {
            Log.d("MY", "failure", e);
        }

        @Override
        public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            } else {
                System.out.println(response.body().string());
            }
        }
    });

...我在 onFailure 中收到此错误:

   java.net.ConnectException: Failed to connect to tastedive.com/2606:4700:30::681c:3a5:443
       at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:242)
       at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:160)
       at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257)
       at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
       at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
       at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
       at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
       at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
       at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
       at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
       at okhttp3.RealCall$AsyncCall.execute(RealCall.java:147)
       at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
       at java.lang.Thread.run(Thread.java:841)
    Caused by: java.net.ConnectException: failed to connect to tastedive.com/2606:4700:30::681c:3a5 (port 443) after 10000ms: isConnected failed: ENETUNREACH (Network is unreachable)
       at libcore.io.IoBridge.isConnected(IoBridge.java:223)
       at libcore.io.IoBridge.connectErrno(IoBridge.java:161)
       at libcore.io.IoBridge.connect(IoBridge.java:112)
       at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
       at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459)
       at java.net.Socket.connect(Socket.java:843)
       at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.java:71)
       at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:240)
       at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:160) 
       at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257) 
       at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135) 
       at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114) 
       at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) 
       at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) 
       at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) 
       at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) 
       at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200) 
       at okhttp3.RealCall$AsyncCall.execute(RealCall.java:147) 
       at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) 
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
       at java.lang.Thread.run(Thread.java:841) 
    Caused by: libcore.io.ErrnoException: isConnected failed: ENETUNREACH (Network is unreachable)
       at libcore.io.IoBridge.isConnected(IoBridge.java:208)
       at libcore.io.IoBridge.connectErrno(IoBridge.java:161) 
       at libcore.io.IoBridge.connect(IoBridge.java:112) 
       at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192) 
       at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459) 
       at java.net.Socket.connect(Socket.java:843) 
       at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.java:71) 
       at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:240) 
       at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:160) 
       at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257) 
       at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135) 
       at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114) 
       at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) 
       at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) 
       at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) 
       at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) 
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) 
       at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200) 
       at okhttp3.RealCall$AsyncCall.execute(RealCall.java:147) 
       at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) 
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
       at java.lang.Thread.run(Thread.java:841) 

我使用的这个 OkHttp 来自 Retrofit 2.4.0。 在模拟器和真实设备上都会发生,但仅在 Kitkat 上。另请注意,异常会立即抛出,而不仅仅是在 10000 毫秒之后。

【问题讨论】:

  • HttpURLConnection 是使用 IPv4 还是 IPv6?看起来 OkHttp 正在尝试 IPv6。
  • @JesseWilson 我该如何解决这个问题?我可以强制 OkHttp 使用 IPv4 吗?
  • 您可以实现 Dns 并剥离 IPv6 地址。委托给 Dns.SYSTEM 类以获取完整集,然后对其进行修剪。
  • @JesseWilson 我想通了!看看我的回答!

标签: android httpurlconnection okhttp android-4.4-kitkat


【解决方案1】:

我解决了!真实设备实际上得到了 Javax.net.ssl.SSLHandshakeException,而模拟器得到了 java.net.ConnectException。这个 * 讨论描述了前 Lollipop 设备的 TLS 存在一个错误。 Javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: Failure in SSL library, usually a protocol error

所以现在我使用这个答案中的代码:https://*.com/a/50640113/9702500,它同时解决了模拟器异常和设备异常:

ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
                .supportsTlsExtensions(true)
                .tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0)
                .cipherSuites(
                        CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
                        CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                        CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
                        CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
                        CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
                        CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                        CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
                        CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
                        CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
                        CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                        CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
                        CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
                .build();
        OkHttpClient client = new OkHttpClient.Builder()
                .connectionSpecs(Collections.singletonList(spec))
                .build();
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://tastedive.com")
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .build();

【讨论】: