在Resteasy中如何在发送响应之前知道客户端连接是否存在

时间:2014-09-16 07:16:52

标签: resteasy

考虑以下方案(使用Rest for Rest实施):

  1. 客户向我的RestService发送了一个请求。
  2. 我的休息服务更新了与请求相关的数据库。
  3. 最后我的休息服务发了一些回复。
  4. 如果客户端超时并在从我的休息服务发送响应之前关闭了他的连接:

    • (我需要)恢复数据库更改。

    问题是:

    如何识别客户是否关闭其连接?

2 个答案:

答案 0 :(得分:1)

Rest是无状态的,您正在尝试跟踪请求状态,这不是可接受的RESTful策略。无论如何,这就是我们在应用程序中解决类似问题的方法。超时可以由会话管理,您可以使用侦听器获取超时事件。但是,关闭'连接似乎有点复杂。有很多黑客你可以从互联网上获得它,但目前还没有普遍接受的浏览器关闭事件。即使问题看起来很简单,但这是一个棘手的问题。您可以尝试以下hack

  • 生成唯一ID并将其与。一起发送到服务器 请求。

  • 在从服务器发送响应之前,安排一个有时间限制的作业,并使用您获得的ID注册该作业。

  • 从客户端,在回调中,您再次使用相同的ID ping服务器。

  • 以这样一种方式安排一个角色:如果它在有限的时间范围内没有从具有注册ID的客户端接收任何ping,则将该功能作为角色。

您也可以查看sockets

答案 1 :(得分:0)

据我所知,RESTeasy和Servlet API都没有提供检查客户端关闭连接的方法。但是已经回答herehere:如果响应大于套接字缓冲区,则底层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中的哪些更改。你可以注射,例如此处HttpHeadersHttpServletRequest来自@Context,可能会设置并检查带有交易ID或类似内容的自定义标头。