【问题标题】:HTTP FAILED: java.net.SocketException: Socket closed; doesn't fire up exception handling methodsHTTP失败:java.net.SocketException:套接字关闭;不启动异常处理方法
【发布时间】:2017-07-09 06:02:09
【问题描述】:

我有一个 RxJava 链请求应该释放一些锁 onError() 或 onComplete(),所以,基本上,我的问题是:当我为我的 OkHttpClient 设置读取、连接和写入超时时,我没有得到期望的行为。我正在使用 Retrofit2 和 OkHttp3.6.0 这是我的简化客户端:

OkHttpClient.Builder builder = new OkHttpClient.Builder()
           .readTimeout(30, TimeUnit.SECONDS)
           .connectTimeout(30, TimeUnit.SECONDS)
           .writeTimeout(30, TimeUnit.SECONDS)
OkHttpClient okHttpClient = builder.build();

这是我的链请求的简化版本:

public <T extends Response> Observable<T> doSomething(Observable<T> base) {
    isLocked = true;
    return someApiCall()
               .flatMap(apiResponse -> handleResponse(apiResponse, base)
                   .doOnError(throwable -> {
                       isLocked = false;
                   })
                   .doOnCompleted(() -> {
                       isLocked = false;
                   }));
}

handleResponse() 进行另一个 API 调用并返回一个 Observable&lt;Response&lt;Something&gt;&gt; 但是,正如我所说,它有时会失败并返回一个 HTTP FAILED: java.net.SocketException: Socket closed 并且它永远不会完成 Observable,因此,onError() 或 onComplete() 永远不会叫。我也尝试过 onTerminate() ,但没有运气。当我从OkHttlClient 中删除超时设置时,SocketException 实际上被抛出并捕获,从而释放了isLocked 变量。我尝试用try {} catch (Exception e) {} 块包装handleResponse() return 语句,但即使设置自定义超时,也无法捕获SocketException。有什么想法吗?

【问题讨论】:

  • handleResponse 是否也进行 Retrofit 调用?您将什么定义为“完成可观察的”?任何问题可能是什么,因为您似乎只是在调用的内部 flatMapped 上应用了 doOnError/Completed,因此 - someApiCall() 可能会失败并且您不会捕获它
  • 是的,它确实进行了改造调用。正如我所提到的,它是一个简化的链,真正的应该是 originalApiCall (fails) -> apiCallOne -> apiCallTwo -> originalApiCall (这是一个会话更新链)我尝试将 doOnError() 和 doOnTerminate 添加到外部调用中,但是没有运气。问题是所有其他异常都被捕获在链中,除了 Socket 关闭
  • 好的,我明白了,那么 SocketException 会发生什么?你怎么知道那是例外?
  • 我只是在 logcat 输出中得到一个单行条目,确切地说:“HTTP FAILED: java.net.SocketException: Socket closed”而且它总是会发生,这不是误报。跨度>
  • 你能附上logcat吗?

标签: android rx-java retrofit2 okhttp


【解决方案1】:

我使用构建器设置的选项 retryOnConnectionFailure(true) 在 Android 中解决了这种情况。

鉴于 Retrofit 2 只接收 OkHttpClient 对象。

【讨论】:

  • 您先生,今天过得愉快
【解决方案2】:

在 Retrofit 2 中,HTTP 层下方/上方的异常不会报告为Response&lt;?&gt;,而是通过onError 报告为实际异常。

在您的情况下,您应该将doOnError/doOnCompleted 移出flatMap;就像现在一样,它们仅响应在 handleResponse 中生成的错误 - 但如果 someApiCall 返回 Observable 错误,则不会调用该方法。

【讨论】:

  • 我知道这一点,我也尝试将 doOnError 和 doOnCompleted 添加到外部调用中,但没有运气,即使是 doOnTerminate 和 doAfterTerminate,它们也永远无法到达(在 Socket 的情况下)例外)。真正的问题是所有其他异常都被链捕获,除了 Socket 关闭,这似乎在其他地方处理......
  • 你能把电话放在defer 中吗?喜欢Observable.defer(()-&gt; someApiCall())
  • 由于我对 RxJava 还很陌生,你能告诉我这有什么好处吗?我会尝试一下,但我不知道会发生什么。
  • defer 将推迟调用 someApiCall() 方法,直到订阅了 Observable。这个想法是您在导致此异常的调用中同步执行某些操作; defer-ing 你应该在订阅中看到它。
【解决方案3】:

原来是请求被退订了,导致出现HTTP FAILED: java.net.SocketException: Socket closed错误,所以,解决办法就是把这段代码加到链上:

.doOnUnsubscribe(() -> {
    isLocked = false;
})

我仍然不明白为什么自定义超时值会触发SocketException,但我认为套接字正在等待超时到期并关闭,或者完成请求并关闭,但它被中断了unsubscribe 调用并因此意外关闭。

【讨论】:

  • 那么是什么导致“套接字关闭”?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-07
  • 1970-01-01
  • 2020-11-16
  • 1970-01-01
  • 1970-01-01
  • 2017-11-24
相关资源
最近更新 更多