Различайте время ожидания подключения и время ожидания чтения с помощью okhttp

Я использую okhttp с лентой, используя spring. Я хочу повторить попытку с другим экземпляром службы по тайм-ауту подключения, но не по тайм-ауту чтения (по очевидным причинам). Эта повторная попытка будет обработана настраиваемым обработчиком повторной попытки ленты. Но чтобы сделать вышеперечисленное, мне нужно различать тайм-ауты чтения и подключения. Поведение с 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)
    

Принятие решения на основе сообщения об исключении не кажется хорошей идеей. Каков рекомендуемый способ достижения этого?


person Tanmay    schedule 30.04.2017    source источник
comment
Следы стека, пожалуйста.   -  person user207421    schedule 30.04.2017
comment
Вы знаете, делаете ли вы подключение или чтение. Вы можете ловить исключения отдельно в каждом случае. Нет никаких трудностей.   -  person user207421    schedule 01.05.2017
comment
Я просто делаю http-вызов. Исключение вызывает библиотека okhttp. Проблема в том, что okhttp выдает одно и то же исключение в обоих случаях, и я не могу расшифровать, является ли это тайм-аутом чтения или тайм-аутом подключения, используя только класс исключения.   -  person Tanmay    schedule 01.05.2017


Ответы (1)


Если вы не хотите полагаться на сообщение, вы также можете выбрать следующие варианты. Однако оба они нуждаются в покрытии JUnit, потому что разработчики OkHttp могут изменить свою реализацию в будущем.

  1. Используйте причину исключения, чтобы решить, как обрабатывать запрос:

    try {
        ...
    } catch (SocketTimeoutException e) {
        if (e.getCause() != null && e.getCause() instanceof SocketTimeoutException) {
            // read timeout
        } else {
            // socket timeout
        }
    }
    
  2. Прокрутите трассировку стека:

    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;
            }
        }
        ...
    }
person Franz Fellner    schedule 01.05.2017