如何使用Jersey ContainerRequestFilter和ContainerResponseFilter匹配http请求和响应

时间:2015-02-20 00:09:11

标签: java rest http jersey

我有一个高度并发的服务器,需要实现一些特殊的日志记录。我需要一种简单的方法来将请求与响应相匹配。 filter()中的ContainerResponseFilter同时包含requestresponse。我怎么都无法访问http帖子内容,因为该流已被读取。

我可以通过某种方式在ID中添加ContainerRequestFilter filter(),并在调用ContainerResponseFilter filter()时自动返回吗?我无法修改真正的应用程序。

我有另一个程序需要处理日志文件,并能够将请求与响应匹配。

还有其他建议吗?

1 个答案:

答案 0 :(得分:0)

我能想到的唯一解决方案是"Cloning the InputStream"another link)。似乎是工作的两倍,但我不知道它是如何实现的(无需编写一堆MessageBodyReaders)。

然后我们可以使用ContainerRequestContext.setProperty(String, Object)设置一个可以在整个请求/响应过滤器链中获得的任意属性。在响应过滤器中,您可以使用ContainerResponseContext.getProperty(String)

这是一个例子,我期待JSON,并使用Jackson ObjectMapper获取JSON Map并获取id值,然后在上下文中设置属性。

@Provider
public class RequestFilter implements ContainerRequestFilter {

    ObjectMapper mapper = new ObjectMapper();

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        if (!requestContext.getMethod().equalsIgnoreCase("POST")) {
            return;
        }

        InputStream entityStream = requestContext.getEntityStream();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = entityStream.read(buffer)) > -1) {
            baos.write(buffer, 0, len);
        }
        baos.flush();

        String contentType = requestContext.getHeaderString(HttpHeaders.CONTENT_TYPE);
        if (MediaType.APPLICATION_JSON.equals(contentType)) {

            // User Jackson ObjectMapper to get JSON as Map
            Map<String, Object> jsonMap = mapper.readValue(
                    new ByteArrayInputStream(baos.toByteArray()),
                    TypeFactory.defaultInstance().constructMapType(
                            Map.class, String.class, Object.class));

            Object id = jsonMap.get("id");
            // Put id into context as property to be retrieved from response filter
            requestContext.setProperty("id", id);
        }

        requestContext.setEntityStream(new ByteArrayInputStream(baos.toByteArray()));
    }
}

以上示例使用Jersey 2.x.如果您使用Jersey 1.x,我在ContainerRequest中没有看到任何设置任何属性的方法,但我想您可以设置一个临时标题

containerRequest.getRequestHeaders().putSingle("X-Temp-ID", id);

然后你可以在响应过滤器中获得标题。