我在运行Android 4.3的模拟器上运行Retrofit有问题,而我的设备运行在Android 4.4.2上,而相同的代码在另一个运行Android 7.1.1的模拟器上正常运行
每次我尝试执行get请求时都会收到超时异常.
java.net.SocketTimeoutException: failed to connect to jsonplaceholder.typicode.com/2606:4700:30::681c:3f5 (port 443) after 10000ms
at libcore.io.IoBridge.connectErrno(IoBridge.java:159)
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:842)
at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.java:73)
at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:246)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:166)
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:254)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:200)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:841)
代码如下
public interface Api {
String BASE_URL = "https://jsonplaceholder.typicode.com/";
@GET("posts")
Call<ArrayList<Post>> getPosts();
}
以及对api的调用
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Api.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
Api api = retrofit.create(Api.class);
Call<ArrayList<Post>> call = api.getPostes();
Log.i("RequestUrl", call.request().url().toString());
call.enqueue(new Callback<ArrayList<Post>>() {
@Override
public void onResponse(Call<ArrayList<Post>> call, Response<ArrayList<Post>> response) {
mPostsList.setValue(response.body());
}
@Override
public void onFailure(Call<ArrayList<Post>> call, Throwable t) {
Log.e("Posts", "Error occurred", t);
}
});
解决方法:
它读取java.net.SocketTimeoutException,它首先建议提高客户端的连接超时值,正如在answer中解释的那样 – 但是在查看okhttp3.internal.platform.AndroidPlatform的当前source code时……这个提示对于不兼容的协议.
服务器的SSL certificate支持TLS 1.0,因为Android 4.x需要它(他们这边没有问题);问题是,当前版本的OkHttp3不再支持TLS 1.0,因此握手不会发生(这就是为什么它抛出这种误导性的SocketTimeoutException而不是SSLHandshakeException).
使用OkHttp3 3.12.x,它仍然应该支持默认配置MODERN_TLS –
但是可以指示OkHttp3 3.13.x使用配置COMPATIBLE_TLS:
/* ConnectionSpec.MODERN_TLS is the default value */
List tlsSpecs = Arrays.asList(ConnectionSpec.MODERN_TLS);
/* providing backwards-compatibility for API lower than Lollipop: */
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
tlsSpecs = Arrays.asList(ConnectionSpec.COMPATIBLE_TLS);
}
OkHttpClient client = new OkHttpClient.Builder()
.connectionSpecs(tlsSpecs)
.build();
还必须将其设置为Retrofit的客户端:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Api.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.setClient(client)
.build();
根据OkHttp3版本,请参阅TLS Configuration History以获取可用的协议支持.看起来,3.12.x甚至已经支持TLS 1.3,因为它将来需要Android Q.甚至可能不需要降级OkHttp3,因为3.12.x的MODERN_TLS仍然支持TLSv1,而在3.13. x它已被移入COMPATIBLE_TLS;还不确定3.14.x.
即使使用当前版本的OkHttp3,仍然可以将所需的TLS 1.0协议添加回ConnectionSpec.COMPATIBLE_TLS,因为这是一个带有方法.add()的ArrayList – 没有任何保证,不会有进一步的不兼容性; 3.12.x可能仍然是支持Android 4.x以后的最佳选择,甚至可能有更新功能的后端.