java – Retrofit不适用于特定版本的android

我在运行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以后的最佳选择,甚至可能有更新功能的后端.

上一篇:android – java.lang.NoClassDefFoundError retrofit2.Utils


下一篇:Android和Java的REST客户端改造不会终止