我正在开发一个即时消息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,这会阻止抛出连接超时错误,因为它会一直重试,直到连接成功,所以我可能得到的唯一超时错误是客户端读取超时?我想知道它会重试多少次以及之后会发生什么。