Android中的HttpURLConnection可以正常工作,但OkHttp在Kitkat上显示“网络无法访问”

时间:2018-11-07 21:34:45

标签: android httpurlconnection okhttp android-4.4-kitkat

我对此特定网站有疑问: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 ms之后,还会立即引发异常。

1 个答案:

答案 0 :(得分:4)

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

因此,现在我使用以下答案中的代码:https://stackoverflow.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();