【问题标题】:AsyncResponse ConnectionCallback does not fire in JerseyAsyncResponse ConnectionCallback 不会在泽西岛触发
【发布时间】:2015-01-03 19:51:45
【问题描述】:

对于异步编程,Jersey (JAX-RS) 提供了一个ConnectionCallback 回调,该回调将在连接断开时执行。来自Jersey docs:

由于一些异步请求可能需要很长时间来处理客户端可能 决定在响应之前终止其与服务器的连接 已恢复或在完全写入客户端之前。到 处理这些用例可以使用 ConnectionCallback。这 仅当连接过早时才会执行回调 在将响应写入背面时终止或丢失 客户。请注意,响应时不会调用此回调 写入成功,客户端连接按预期关闭。

听起来不错,但我永远无法点燃它。

这里有一些代码:

@GET
@Produces(MediaType.TEXT_PLAIN)
@ManagedAsync
@Path("/poll")
public void poll(@Suspended final AsyncResponse asyncResponse) {
    asyncResponse.register(new CompletionCallback() {
        @Override
        public void onComplete(Throwable throwable) {
            logger.info("onComplete called.");
        }
    });

    asyncResponse.register(new ConnectionCallback() {
        @Override
        public void onDisconnect(AsyncResponse disconnected) {
            logger.info("onDisconnect called.");
        }
    });

    asyncResponse.setTimeout(POLL_TIMEOUT_SECONDS, TimeUnit.SECONDS);
    asyncResponse.setTimeoutHandler(new TimeoutHandler() {
        @Override
        public void handleTimeout(AsyncResponse asyncResponse) {
            logger.info("handleTimeout called.");
            asyncResponse.resume(Response.status(Response.Status.OK).entity("TIMEOUT").build());
        }
    });
}

显示的另外两个回调,CompletionCallback 和 TimeoutHandler,触发得很好,没有失败。如果达到指定的超时持续时间,TimeoutHandler 将触发。如果 AsyncResponse 实例被恢复,则 CompletionCallback 触发。

但是,使用 ConnectionCallback,我可以关闭、终止或以其他方式停止连接到上面显示的 Web 服务的客户端,并且 ConnectionCallback 永远不会被触发。

我错过了什么吗? ConnectionCallback 是否在泽西岛实现? (在 JAX-RS 规范中它是可选的,但 Jersey 文档谈论它好像它已经实现了。)

我们将不胜感激。

【问题讨论】:

    标签: java web-services asynchronous jersey jersey-2.0


    【解决方案1】:

    ConnectionCallback 确实在 Jersey 中实现。并且还调用了“onDisconnect”回调。您可以在 Jersey 中查看以下代码:

    https://github.com/jersey/jersey/blob/a6ff4d50da13d45ad90fd7375a15a31afa02e489/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java#L723

    https://github.com/jersey/jersey/blob/b7907e279010e7035a7a3e529993d22f77a21e08/core-server/src/main/java/org/glassfish/jersey/server/ChunkedOutput.java#L246-L252

    在写响应时抛出 IOException。因此,为了回答您的问题,没有轮询或类似机制不断检查客户端是否已连接,而是仅在写入响应时通常发生 IOException 时才调用 onDisconnect 方法。

    更新 1:

    另外我想引用你自己的问题:

    "只有在连接过早的情况下才会执行此回调 在将响应写入背面时终止或丢失 客户”

    因此,除非您尝试写入该流,否则您的回调将永远不会被触发。需要明确的是,当没有写入响应或响应为 202 时调用它并不意味着调用它,而是意味着当连接过早终止时调用它在写入响应时。

    恐怕没有解决此问题的方法,除非您编写一些带有某种轮询的低级网络编程。但我不建议你这样做。

    我建议您重新考虑处理此故障的方式。

    【讨论】:

    • 您好,感谢您的回答。我已经确定它是在泽西岛实现的,尽管在我的调试中我永远无法通过各种终止客户端连接的方式触发onDisconnect,尽管这可能是特定于环境的。另外,为了赏金,我需要知道如何处理 onDisconnect 似乎只会在尝试编写响应之后才会发生的事实,即在您认为请求完成以及为什么在没有实体时不引用它之后写(try catch 只是围绕写实体,而不是 204)
    • 您好,感谢您的更新,无论在编写 202 响应时是否应该调用它,因为即使没有正文,它仍在向客户端发送响应。 javadoc 声明“如果容器检测到与异步响应关联的远程客户端连接已断开,则会调用此回调通知方法。”。因此,即使它在完成请求后确实调用了 onDisconnect(我猜这很好),如果正在写入非正文响应,它也不会。
    • 我认为你说得对,不过我需要另一种方式来考虑它......我真的在尝试解决一个外部强加的约束,它只会导致糟糕的 API 设计! :S
    • 如果您想处理响应完成,您已经拥有CompletionCallback,正如您在问题中提到的那样。我猜它会在 202 年被解雇。
    猜你喜欢
    • 1970-01-01
    • 2014-10-06
    • 1970-01-01
    • 2011-08-02
    • 1970-01-01
    • 2012-09-19
    • 2017-05-13
    • 2013-12-21
    • 1970-01-01
    相关资源
    最近更新 更多