我使用Spring使用okhttp与功能区。我希望在连接超时时在另一个服务实例上重试,但不要在阅读超时(出于明显的原因(上重试。此重试将由定制的缎带重试处理程序处理。但是要做上述情况,我需要区分阅读和连接超时。OKHTTP的行为如下:
-
在阅读超时:
java.net.SocketTimeoutException: timeout at okio.Okio$3.newTimeoutException(Okio.java:212) at okio.AsyncTimeout.exit(AsyncTimeout.java:288) at okio.AsyncTimeout$2.read(AsyncTimeout.java:242) at okio.RealBufferedSource.indexOf(RealBufferedSource.java:325) at okio.RealBufferedSource.indexOf(RealBufferedSource.java:314) at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:210) at okhttp3.internal.http.Http1xStream.readResponse(Http1xStream.java:184) at okhttp3.internal.http.Http1xStream.readResponseHeaders(Http1xStream.java:125) at okhttp3.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:775) at okhttp3.internal.http.HttpEngine.access$200(HttpEngine.java:86) at okhttp3.internal.http.HttpEngine$NetworkInterceptorChain.proceed(HttpEngine.java:760) at okhttp3.internal.http.HttpEngine.readResponse(HttpEngine.java:613) at okhttp3.RealCall.getResponse(RealCall.java:244) at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:201) at com.bluejeans.sample.test.OkHttpConnect$1.intercept(OkHttpConnect.java:25) at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:190) at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:163) at okhttp3.RealCall.execute(RealCall.java:57) at com.bluejeans.sample.test.OkHttpConnect.main(OkHttpConnect.java:39) Caused by: java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:170) at java.net.SocketInputStream.read(SocketInputStream.java:141) at okio.Okio$2.read(Okio.java:140) at okio.AsyncTimeout$2.read(AsyncTimeout.java:238) ... 16 more
-
在连接超时:
java.net.SocketTimeoutException: connect timed out at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at okhttp3.internal.Platform.connectSocket(Platform.java:121) at okhttp3.internal.io.RealConnection.connectSocket(RealConnection.java:185) at okhttp3.internal.io.RealConnection.buildConnection(RealConnection.java:170) at okhttp3.internal.io.RealConnection.connect(RealConnection.java:111) at okhttp3.internal.http.StreamAllocation.findConnection(StreamAllocation.java:187) at okhttp3.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:123) at okhttp3.internal.http.StreamAllocation.newStream(StreamAllocation.java:93) at okhttp3.internal.http.HttpEngine.connect(HttpEngine.java:296) at okhttp3.internal.http.HttpEngine.sendRequest(HttpEngine.java:248) at okhttp3.RealCall.getResponse(RealCall.java:243) at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:201) at com.bluejeans.sample.test.OkHttpConnect$1.intercept(OkHttpConnect.java:25) at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:190) at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:163) at okhttp3.RealCall.execute(RealCall.java:57) at com.bluejeans.sample.test.OkHttpConnect.main(OkHttpConnect.java:39)
根据异常消息决定似乎不是一个好主意。推荐的方法是什么?
如果您不想依靠消息,则可能还可以选择以下选项。但是,他们俩都需要Junit覆盖范围,因为Okhttp的开发人员将来可能会改变其实施。
-
使用例外原因来决定如何治疗请求:
try { ... } catch (SocketTimeoutException e) { if (e.getCause() != null && e.getCause() instanceof SocketTimeoutException) { // read timeout } else { // socket timeout } }
-
通过堆栈跟踪循环:
try { ... } catch (SocketTimeoutException e) { boolean isConnectException = false; for (StackTraceElement elem : e.getStackTrace()) { if ("java.net.Socket".equals(elem.getClassName()) && "connect".equals(elem.getMethodName())) { isConnectException = true; break; } } ... }