AsyncResponse ConnectionCallback 不会在泽西岛触发
Posted
技术标签:
【中文标题】AsyncResponse ConnectionCallback 不会在泽西岛触发【英文标题】:AsyncResponse ConnectionCallback does not fire in Jersey 【发布时间】: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 文档谈论它好像它已经实现了。)
我们将不胜感激。
【问题讨论】:
【参考方案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 年被解雇。以上是关于AsyncResponse ConnectionCallback 不会在泽西岛触发的主要内容,如果未能解决你的问题,请参考以下文章