考虑以下方案(使用Rest for Rest实施):
如果客户端超时并在从我的休息服务发送响应之前关闭了他的连接:
问题是:
如何识别客户是否关闭其连接?
答案 0 :(得分:1)
Rest是无状态的,您正在尝试跟踪请求状态,这不是可接受的RESTful策略。无论如何,这就是我们在应用程序中解决类似问题的方法。超时可以由会话管理,您可以使用侦听器获取超时事件。但是,关闭'连接似乎有点复杂。有很多黑客你可以从互联网上获得它,但目前还没有普遍接受的浏览器关闭事件。即使问题看起来很简单,但这是一个棘手的问题。您可以尝试以下hack
生成唯一ID并将其与。一起发送到服务器 请求。
在从服务器发送响应之前,安排一个有时间限制的作业,并使用您获得的ID注册该作业。
从客户端,在回调中,您再次使用相同的ID ping服务器。
以这样一种方式安排一个角色:如果它在有限的时间范围内没有从具有注册ID的客户端接收任何ping,则将该功能作为角色。
您也可以查看sockets。
答案 1 :(得分:0)
据我所知,RESTeasy和Servlet API都没有提供检查客户端关闭连接的方法。但是已经回答here和here:如果响应大于套接字缓冲区,则底层servlet容器可能抛出IOException
。
你可以轻松地测试一下:
测试客户端
@Test
public void testTimeout() throws Exception {
URLConnection connection = new URL("http://yourhost.com/foo").openConnection();
connection.setReadTimeout(1000);
connection.getContent();
}
资源类
@Path("/foo")
public class SomeResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public Response test() throws InterruptedException {
Thread.sleep(5000l);
String response = RandomStringUtils.random(6000);
return Response.ok(response).build();
}
}
使用RESTeasy 3.0.6.Final在Wildlfy 8.1.0上为我工作6000个字符。
由于在执行“您的”代码后很长时间抛出此异常,您无法在资源类或异常映射器中捕获异常。唯一的方法是实施WriterInterceptor:
@Provider
public class ResponseInterceptor implements WriterInterceptor {
@Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
try {
context.proceed();
} catch (IOException ex) {
if (ex.getMessage().contains("Broken pipe")) { // ugly but seems like the only chance...
// revert DB changes
}
}
}
}
这里您不知道应该还原DB中的哪些更改。你可以注射,例如此处HttpHeaders
或HttpServletRequest
来自@Context
,可能会设置并检查带有交易ID或类似内容的自定义标头。