2015-01-22 2 views
2

У меня есть фильтр LogginFilter, зарегистрированный для ResourceConfig.jersey 2 logging и gzip

// Enable logging of requests 
registerInstances(new LoggingFilter(java.util.logging.Logger.getLogger(this.getClass().getName()), 
     true)); 

У меня также включен фильтр GZIPEncoding, поэтому ответ будет сжат для клиентов, которые его поддерживают.

// Encode gzip responses if request header supports it 
EncodingFilter.enableFor(this, GZipEncoder.class); 

Но проблема в том, что этот фильтр регистрации выводит сжатый объект ответа, т.е. после сжатия и не раньше, так что вывод выглядит так, что делает его довольно бесполезным и невозможно увидеть, что возвращается.

INFO: 78 * Server responded with a response on thread http-bio-8443-exec-5 78 < 200 78 < Content-Type: application/json ^_^@^@^@^@^@^@^@

я могу отключить GZIPEncoder и ответ записывается несжатый но объект ответа также передается в несжатом ...

Кто-нибудь есть предложение, как избежать этой проблемы и сделать возможным для поддержки поддержки GZIP на стороне сервера, в то же время отлаживая данные ответа простым текстом и не сжимая.

Я был бы благодарен за помощь.

Благодаря уважением

ответ

0

Это не может быть то, что вы думаете. Я был озадачен некоторое время с той же проблемой, я думал, что это проблема с ответом сервера. Запрос выглядит просто отлично, но вывод усечен до нескольких строк. Существует конструктор для LoggingFilter, где вы можете установить максимальный размер сущности. Размер буфера по умолчанию очень мал для ответа. Довольно уверен, что это ваша проблема.

https://jersey.java.net/apidocs/latest/jersey/org/glassfish/jersey/filter/LoggingFilter.html

Creates a logging filter with custom logger and entity logging turned on, but potentially limiting the size of entity to be buffered and logged. 
LoggingFilter(Logger logger, int maxEntitySize) 
+0

Привет Крис, я видел это, когда глядя на LoggingFilter Javadoc, но это не моя проблема, по умолчанию 8k достаточно, по крайней мере показать вам первые несколько строк из сущности и обрезает все остальное, и в моем это мусор полностью, также при отключении GZIPEncoder весь отклик принтеров, поэтому проблема связана с кодировщиком. Если у кого-то нет решения для меня, мне нужно будет создать копию LoggingFilter и немного изменить его, чтобы проверить заголовок перед печатью, и если содержимое gzip/deflate распаковывает поток перед печатью. – okram123

0

Мы также имели те же требования регистрации четкий текст полезной нагрузки при сжатии его. Вот как я это сделал. Этот пример предназначен для того, когда клиент http запросил Accept-Encoding: gzip.

У вас будет класс GZIPWriterFilterInterceptor, который реализует интерфейсы фильтра Джерси и Interceptor.

import java.io.BufferedInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.util.List; 
import java.util.Map.Entry; 
import java.util.UUID; 

import javax.annotation.Priority; 
import javax.ws.rs.Priorities; 
import javax.ws.rs.WebApplicationException; 
import javax.ws.rs.container.ContainerRequestContext; 
import javax.ws.rs.container.ContainerRequestFilter; 
import javax.ws.rs.core.MultivaluedMap; 
import javax.ws.rs.core.Request; 
import javax.ws.rs.ext.Provider; 
import javax.ws.rs.ext.WriterInterceptor; 
import javax.ws.rs.ext.WriterInterceptorContext; 

import org.apache.commons.io.output.TeeOutputStream; 
@Provider 
@Priority(Priorities.ENTITY_CODER) 
@Compress 
public class GZIPWriterFilterInterceptor implements ContainerResponseFilter, WriterInterceptor 
{ 
/** 
* http header value for Accept-Encoding 
*/ 
public static final String GZIP = "gzip"; 



protected GZIPOutputStream getGZIPOutputStream(final OutputStream outputStream) throws IOException 
{ 
    return new GZIPOutputStream(outputStream); 
} 

@Override 
public void filter(final ContainerRequestContext requestContext, 
     final ContainerResponseContext responseContext) throws IOException 
{ 
    final MultivaluedMap<String,String> headers = requestContext.getHeaders(); 
    //if client has requested with HttpHeader of Accept-Encoding: gzip, 
    //then do gzip encoding and put Content-Coding: gzip as part of response 
    if(headers != null && headers.get(HttpHeaders.ACCEPT_ENCODING) != null) 
    { 
     for(final String header : headers.get(HttpHeaders.ACCEPT_ENCODING)) 
     { 
      if(header.contains(GZIP)) 
      { 
responseContext.getHeaders().add(HttpHeaders.CONTENT_ENCODING, GZIP); 
        break; 
      } 
     } 
    } 
} 

@Override 
public void aroundWriteTo(final WriterInterceptorContext context) 
     throws IOException, WebApplicationException 
{ 
    if(context.getHeaders() != null && context.getHeaders().containsKey(HttpHeaders.CONTENT_ENCODING) 
      && context.getHeaders().get(HttpHeaders.CONTENT_ENCODING).contains(GZIP)) 
    { 
     // for the response, there is only one outputstream i.e. written to by jersey after all the 
     // interceptors have invoked context.proceed() in their aroundWriteTo method. 
     // so when we wrap the base outputstream in a GZIPOutputStream, the response will be GZIP encoded. 
     // but we also want to log the payload. Hence we use TeeOutputStream to "clone" the base outputstream. 
     // As a result, jersey will write directly to TeeOutputStream, which in turn will forward the writes to 
     // both GZIPOutputStream and ByteArrayOutputStream. We also store the ByteArrayOutputStream in context 
     // so that it can be accessed by APILoggingFilter. 
     final ByteArrayOutputStream boas = new ByteArrayOutputStream(); 

     final OutputStream outputStream = context.getOutputStream(); 
     context.setOutputStream(new TeeOutputStream(getGZIPOutputStream(outputStream) 
       , boas)); 
     context.setProperty(Constants.ENTITY_LOGGER_PROPERTY, boas); 

    } 
    context.proceed(); 
} 
} 

Обратите внимание, что мы клонируем выходной поток с помощью TeeOutputStream от Apache.

Все, что вам нужно, это сжатое определение аннотации, а затем вы можете аннотировать свой метод ресурсов с помощью @Compress. Также укажите имя пакета этого класса в вашем web.xml.

@NameBinding 
@Retention(RetentionPolicy.RUNTIME) 
public @interface Compress 
{ 

} 

Вот соответствующий фрагмент web.xml

<servlet> 
    <servlet-name>MY Web Application</servlet-name> 
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> 
    <init-param> 
     <param-name>jersey.config.server.provider.packages</param-name> 
     <param-value>com.my.gzip.logging.jaxrs.filters.package</param-value> 
    </init-param> 

    <load-on-startup>1</load-on-startup> 
</servlet> 

Если вы хотите сделать регистрацию полезной нагрузки, вы можете добавить еще один фильтр Джерси/перехватчик. Вот как будет выглядеть метод aroundWriteTo.

public void aroundWriteTo(final WriterInterceptorContext context) throws IOException, WebApplicationException 
{ 
    if (context != null) 
    { 
     ByteArrayOutputStream stream = (ByteArrayOutputStream) context.getProperty(ENTITY_LOGGER_PROPERTY); 
     if(stream == null) 
     { 
      //it means the GZIPWriter is not hooked in. 
      stream = new ByteArrayOutputStream(); 

      final OutputStream outputStream = context.getOutputStream(); 
      context.setOutputStream(new TeeOutputStream(outputStream, stream)); 
     } 
     context.proceed(); 

     final String message = stream == null ? "no entity" : stream.toString(); 
     Logger.end(context, message); 


    } 
} 
Смежные вопросы