如何断开 OkHttp3 sse 连接?



问题:

我正在尝试创建一个可以使用SSE(服务器发送的事件(从服务器接收事件的客户端,我正在使用OkHttp3来做到这一点,并结合OkHttp3-sse库(com.squareup.okhttp3:okhttp:4.1.0和com.squareup.okhttp3:okhttp-sse:4.1.0(。 我能够连接到服务器并很好地接收事件,但在某个时间点,我想断开客户端并关闭我的应用程序。这就是问题所在。连接已关闭,但应用程序未关闭,可能是由于ConnectionPool未关闭。

企图:

由于几乎没有任何关于使用 OkHttp3-sse 库的文档,因此我尝试从代码中逆向工程该怎么做。我尝试:

  • 调用正在断开连接但挂在线程上的RealEventSource.cancel()
  • 调用OkHttpClient.dispatcher().cancelAll()也断开连接,但仍挂在线程上
  • 调用传递给EventSourceListener.onOpen()Response.close()

发现:

作为替代方案,我已经查看了 https://github.com/heremaps/oksse 具有RealServerSentEvent.close()调用的功能,该调用正在执行我的期望。它关闭连接并停止所有线程,允许应用程序完全关闭。 我查看了RealServerSentEvent类的实现,以了解实现与RealEventSource有何不同。我认为区别在于读取循环的条件:

RealEventSource行 https://github.com/square/okhttp/blob/master/okhttp-sse/src/main/java/okhttp3/internal/sse/RealEventSource.kt#L75:

try {
listener.onOpen(this, response)
while (reader.processNextEvent()) {
}
} catch (e: Exception) {
listener.onFailure(this, e, response)
return
}

比较RealServerSentEvent行 https://github.com/heremaps/oksse/blob/master/src/main/java/com/here/oksse/RealServerSentEvent.java#L94:

listener.onOpen(this, response);
//noinspection StatementWithEmptyBody
while (call != null && !call.isCanceled() && sseReader.read()) {
}

OkSSE实现包括条件,如果循环中的call.isCanceled(),而OkHttp3-sse则不这样做。我怀疑这导致OkHttp3-sse不退出,但我可能弄错了。

或者,我是否在监督预期的断开连接方式?

最终我发现可以通过调用以下命令优雅地关闭连接:

eventSource.cancel();
client.dispatcher().executorService().shutdown();

由于这不需要对库进行任何更改,因此我关闭了错误报告。

您正确使用了 API,当调用被取消时,OkHttp 应该会导致读取失败并显示 IOException。显然,这并没有发生,我将其视为OkHttp中的错误。

后续步骤:将错误报告给 OkHttp。如果您可以使用可执行的测试用例来做到这一点,我将确保这个问题很快得到修复。

最新更新