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

Java 在改造okhttp3时,如何以不同方式处理连接超时和客户端超时,java,retrofit,socket-timeout-exception,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.AsyncT

我正在开发一个即时消息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:?]
通过查看堆栈跟踪,我发现这是客户端读取超时而不是连接超时,服务器实际收到了我的请求,后端逻辑已正确执行,但我的客户端未能从服务器读取响应

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

如果我吞下了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,这是否会防止抛出连接超时错误,因为它会一直重试,直到连接成功,所以我可能得到的唯一超时错误是客户端读取超时?我想知道它会重试多少次,之后会发生什么。

AFAIK,总是客户端超时,服务器会正常执行,但是执行时间可能太长(比超时时间长),客户端定义的持续时间太长,所以客户端会引发异常,服务器在发送响应之前要花费多少时间?尝试在clientThx上增加回复的超时时间。当我构造okhttp客户端时,连接超时和客户端读取超时的设置都是30秒。服务器的响应时间应少于1秒,但有时网络本身可能不可靠。这是个罕见的病例,但我还是遇到了。如果像你说的,总是客户端超时,我想我可以抛出异常,而不是继续重试,让我的用户决定需要采取什么进一步的行动。我可能想澄清这一点,我的意思是大部分是(读取超时),因为你确认请求到达了服务器,但响应没有到达客户端,但是,伪(盲)重试是不明智的,特别是在您的情况下,存在重复/唯一问题,请问您是否自行设置超时或将其保留为默认值,如果您这样做,您是否可以显示您使用的代码?因为30秒应该以毫秒为单位输入,这将是(30000),您需要考虑使事务幂等。@Yazan不必担心时间,okhttp客户端生成器正在使用connectTimeout(长超时,时间单位)并设置它,而不是毫秒。我将更新我的问题并添加我使用的代码。