HttpURLConnection в Android работает нормально, но OkHttp выдает «Сеть недоступна» на Kitkat - PullRequest
0 голосов
/ 08 ноября 2018

У меня проблема с этим конкретным сайтом: https://tastedive.com/read/api

Если я выполняю HTTP-запрос с HttpURLConnection, я получаю обычный 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 мс.

1 Ответ

0 голосов
/ 10 ноября 2018

Я решил это! Реальное устройство фактически получало Javax.net.ssl.SSLHandshakeException, в то время как эмулятор получал java.net.ConnectException. В этом обсуждении StackOverflow описывается ошибка вокруг TLS для устройств, предшествующих Lollipop. Javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: сбой рукопожатия SSL: сбой в библиотеке SSL, обычно ошибка протокола

Так что теперь я использую этот код из этого ответа: 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();
...