在使用okhttp3进行改造时,如何以不同方式处理连接超时和客户端超时

时间:2017-04-23 03:58:19

标签: java retrofit socket-timeout-exception

我正在开发一个即时消息REST客户端库,它使用改装v2.1.0与属于第三方的REST服务器通信(我无法触及服务器端的代码或逻辑)。

出于某种原因,我在同步调用接口时不断收到java.net.SocketTimeoutException。

java.net.SocketTimeoutException: timeout
    at okio.Okio$3.newTimeoutException(Okio.java:212) ~[okio-1.8.0.jar:?]
    at okio.AsyncTimeout.exit(AsyncTimeout.java:288) ~[okio-1.8.0.jar:?]
    at okio.AsyncTimeout$2.read(AsyncTimeout.java:242) ~[okio-1.8.0.jar:?]
    at okio.RealBufferedSource.indexOf(RealBufferedSource.java:325) ~[okio-1.8.0.jar:?]
    at okio.RealBufferedSource.indexOf(RealBufferedSource.java:314) ~[okio-1.8.0.jar:?]
    at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:210) ~[okio-1.8.0.jar:?]
    at okhttp3.internal.http.Http1xStream.readResponse(Http1xStream.java:184) ~[okhttp-3.3.0.jar:?]
    at okhttp3.internal.http.Http1xStream.readResponseHeaders(Http1xStream.java:125) ~[okhttp-3.3.0.jar:?]
    at okhttp3.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:775) ~[okhttp-3.3.0.jar:?]
    at okhttp3.internal.http.HttpEngine.access$200(HttpEngine.java:86) ~[okhttp-3.3.0.jar:?]
    at okhttp3.internal.http.HttpEngine$NetworkInterceptorChain.proceed(HttpEngine.java:760) ~[okhttp-3.3.0.jar:?]
    at okhttp3.internal.http.HttpEngine.readResponse(HttpEngine.java:613) ~[okhttp-3.3.0.jar:?]
    at okhttp3.RealCall.getResponse(RealCall.java:244) ~[okhttp-3.3.0.jar:?]
    at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:201) ~[okhttp-3.3.0.jar:?]
    at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:163) ~[okhttp-3.3.0.jar:?]
    at okhttp3.RealCall.execute(RealCall.java:57) ~[okhttp-3.3.0.jar:?]
    at retrofit2.OkHttpCall.execute(OkHttpCall.java:174) ~[retrofit-2.1.0.jar:?]

通过查看堆栈跟踪,我发现它是客户端读取超时而不是连接超时,服务器实际接收到我的请求,后端逻辑已正确执行,但我的客户端无法从服务器读取响应。 / p>

如果我继续重试,服务器将收到重复的请求,这可能导致向另一个客户端发送重复的消息。如果我删除客户端读取超时异常会产生严重后果,但作为库,如果我可以通知我的库的用户实际发生此异常,他们可以选择忽略或采取其他必要的操作,那会更好。

如果我吞下SocketTimeoutException,并且实际上是连接超时,服务器可能永远不会收到我的请求,我将丢失来自其他客户端的消息。

任何想法如何实现确定我得到的SocketTimeoutException的目标是客户端读取超时或连接超时,并且只在连接超时时重试?

更新1

我用来创建okhttp客户端和改造服务的代码:

public SampleApi createSampleService() {
    OkHttpClient.Builder clientBuilder = new OkHttpClient().newBuilder()
            .retryOnConnectionFailure(true)
            .connectTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS);
            .readTimeout(30, TimeUnit.SECONDS);
    return new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(clientBuilder.build())
            .build()
            .create(SampleApi.class);
}

我在这里将retryOnConnectionFailure设置为true,这会阻止抛出连接超时错误,因为它会一直重试,直到连接成功,所以我可能得到的唯一超时错误是客户端读取超时?我想知道它会重试多少次以及之后会发生什么。

0 个答案:

没有答案
相关问题