我想在JAX-RS过滤器中捕获并记录响应有效负载。这是我用来拦截响应的过滤器方法的代码片段。 (仅供参考 - 我正在使用RestEasy进行实施)
@Override
public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext) throws IOException {
...
final OutputStream out = responseContext.getEntityStream();
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
out.write(baos.toByteArray());
....
}
}
但是,ByteArrayOutputStream结果为空。查看RestEasy代码,它使用的是DeferredOutputStream,但不确定在拉动响应有效负载时这将如何重要。我曾尝试直接写入byte [],但这也无济于事。我在这里错过了什么吗?感谢。
答案 0 :(得分:19)
如果您不想在回复中写入更多数据,则无需处理OutputStream。只需使用响应实体:
@Provider
public class SomeFilter implements ContainerResponseFilter {
private Logger LOG = LoggerFactory.getLogger(SomeFilter.class);
@Override
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext) throws IOException {
LOG.info("response entity: " + responseContext.getEntity());
}
}
调用Filter时OutputStream为空,因为JAX-RS运行时没有写入它。在过滤后,运行时将选择正确的MessageBodyWriter,它将实体序列化为OutputStream。
您还可以使用WriterInterceptor拦截所有MessageBodyWriters。下面的示例将ByteArrayOutputStream传递给MessageBodyWriter,然后恢复原始的OutputStream:
@Provider
public class ResponseInterceptor implements WriterInterceptor {
private Logger LOG = LoggerFactory.getLogger(ResponseInterceptor.class);
@Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
OutputStream originalStream = context.getOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
context.setOutputStream(baos);
try {
context.proceed();
} finally {
LOG.info("response body: " + baos.toString("UTF-8"));
baos.writeTo(originalStream);
baos.close();
context.setOutputStream(originalStream);
}
}
}
答案 1 :(得分:2)
我遇到了同样的问题并且解决了不同的问题,所以我也留下了我的回复,尽管这个问题已经标记为正确答案了。
我实施了ContainerResponseFilter
并注入了Providers
,我通过该MessageBodyWriter
检索了响应的特定实体和特定MediaType
的{{1}};然后我用它将实体写入一个可访问的OutputStream
,我用它来记录实体。
这种方法允许您捕获响应的确切有效负载,而不仅仅是附加到Response
的实体,即如果实体将被序列化为JSON,那么您将记录JSON,如果它被序列化为XML,您将记录XML。如果使用附加实体的toString()
方法就足够了,这种方法只是一种无用的计算成本。
这是代码(技巧在函数CustomResponseLogger.payloadMessage
中完成):
@Provider
public class CustomResponseLogger implements ContainerResponseFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomResponseLogger.class);
@Context private Providers providers;
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
String message = new String("Outgoing message").concat(System.lineSeparator());
if (responseContext.getMediaType() != null)
message = message.concat("Content-Type: ").concat(responseContext.getMediaType().toString()).concat(System.lineSeparator());
message = message.concat("Payload: ").concat(payloadMessage(responseContext)).concat(System.lineSeparator());
LOGGER.info(message);
}
private String payloadMessage(ContainerResponseContext responseContext) throws IOException {
String message = new String();
if (responseContext.hasEntity()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Class<?> entityClass = responseContext.getEntityClass();
Type entityType = responseContext.getEntityType();
Annotation[] entityAnnotations = responseContext.getEntityAnnotations();
MediaType mediaType = responseContext.getMediaType();
@SuppressWarnings("unchecked")
MessageBodyWriter<Object> bodyWriter = (MessageBodyWriter<Object>) providers.getMessageBodyWriter(entityClass,
entityType,
entityAnnotations,
mediaType); // I retrieve the bodywriter
bodyWriter.writeTo(responseContext.getEntity(),
entityClass,
entityType,
entityAnnotations,
mediaType,
responseContext.getHeaders(),
baos); // I use the bodywriter to write to an accessible outputStream
message = message.concat(new String(baos.toByteArray())); // I convert the stream to a String
}
return message;
}
}
希望这有帮助!