如何使用Jersey ContainerRequestFilter和ContainerResponseFilter匹配http请求和响应 [英] How to match http request and response using Jersey ContainerRequestFilter and ContainerResponseFilter
问题描述
我有一个高度并发的服务器,需要实现一些特殊的日志记录。我需要一种简单的方法来将请求与响应相匹配。 ContainerResponseFilter
中的过滤器()
同时包含请求
和响应
。我怎么都无法访问http帖子内容,因为该流已被读取。
I have a highly concurrent server and need to implement some special logging. I need an easy way to match the request to the response. The filter()
in ContainerResponseFilter
has both the request
and response
. How ever I can not access the http post content because the stream has already been read.
我是否可以通过某种方式添加 ID
在 ContainerRequestFilter过滤器()
中以及 ContainerResponseFilter过滤器()
时自动返回叫什么名字?我无法修改真正的应用程序。
Is there some way I can add an ID
in the ContainerRequestFilter filter()
and somehow have it automatically returned when the ContainerResponseFilter filter()
is called? I can not modify the true applications.
我有另一个程序需要处理日志文件并能够将请求与响应匹配。
I have another program that will need to process the log file and be able to match the request to the response.
还有其他任何建议吗?
推荐答案
我能想到的唯一解决方案克隆InputStream(其他链接)。似乎是工作的两倍,但我不知道它是如何实现的(无需编写一堆MessageBodyReaders)。
The only solutions I can think of invloves "Cloning the InputStream" (another link). Seems like double the work, but I don't see how else it can be achieved (without having to write a bunch of MessageBodyReaders).
然后我们可以使用 ContainerRequestContext.setProperty(String,Object)
设置一个可以在整个请求/响应过滤器链中获得的任意属性。在响应过滤器中,您可以使用 ContainerResponseContext.getProperty(String)
。
Then we can just use ContainerRequestContext.setProperty(String, Object)
to set an arbitrary property than can be obtained throughout the request/response filter chain. In the response filter, you can use ContainerResponseContext.getProperty(String)
.
这是一个例子,我期待JSON,并使用Jackson ObjectMapper获取JSON Map并获得 id
value,然后在上下文中设置属性。
Here's an example, where I am expecting JSON, and using Jackson ObjectMapper to get a JSON Map and getting the id
value, then setting the property in the context.
@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
中看不到任何方法来设置任何属性,但我想你可以设置一个临时标题
The above example uses Jersey 2.x. If you are using Jersey 1.x, I don't see any method in the ContainerRequest
to set any arbitrary property, but I guess you could just set a temporary header
containerRequest.getRequestHeaders().putSingle("X-Temp-ID", id);
然后你可以在响应过滤器中获得标题。
Then you can just get the header in the response filter.
这篇关于如何使用Jersey ContainerRequestFilter和ContainerResponseFilter匹配http请求和响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!