Захват полезной нагрузки ответа в фильтре JAX-RS
Я хочу захватить и зарегистрировать полезную нагрузку ответа в фильтре 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[] напрямую, но это тоже не помогает. Неужели я пропал? здесь есть что-нибудь ? Спасибо.
2 ответа:
Если вы не хотите записывать больше данных в ответ, вам не нужно иметь дело с потоком вывода. Просто используйте объект ответа:
@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()); } }
Выходной поток пуст в момент вызова фильтра, поскольку среда выполнения JAX-RS не записала в него данные. После вашего фильтра среда выполнения выберет правильный MessageBodyWriter , который сериализует сущность в выходной поток.
Вы можете также перехватить все экземпляры этого класса с WriterInterceptor. Следующем примере передается bytearrayoutputstream не, чтобы передать среде провайдер и восстанавливает первоначальный клиенту 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); } } }
У меня была та же проблема, но решенная по-другому, поэтому я оставляю здесь свой ответ, хотя вопрос уже помечен как правильно отвеченный.
Я реализовал
ContainerResponseFilter
и ввелProviders
, через которые я извлекMessageBodyWriter
для конкретной сущности ответа и конкретнойMediaType
; Затем я использовал его для записи сущности в доступный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; } }
Надеюсь, это поможет!