Android中的HttpURLConnection工作正常,但OkHttp在Kitkat上提供了"Network is unreachable"



我对这个特定的站点有问题: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来自于改装2.4.0。在模拟器和真实设备上都会发生,但仅在Kitkat上发生。还要注意,异常会立即抛出,而不仅仅是在10000毫秒之后。

我解决了它!实际的设备实际上得到了Javax.net.ssl.ssl握手异常,而模拟器得到了java.net.ConnectException。这个StackOverflow讨论描述了Lollipop之前的设备存在TLS漏洞。Javax.net.ssl.ssl握手异常:Javax.net.ssl.ssl协议异常: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();

相关内容

最新更新