2013-05-19 43 views
7

Tôi đã một client gửi đi dữ liệu vớiLàm thế nào để giải mã Gzip cơ thể yêu cầu nén trong Spring MVC

CONTENT-ENCODING deflate 

tôi có mã như thế này

@RequestMapping(value = "/connect", method = RequestMethod.POST) 
@ResponseBody 
public Map onConnect(@RequestBody String body){} 

Hiện nay 'body' in ra bị cắt xén, nén dữ liệu. Có cách nào để Spring MVC tự động giải nén không?

+2

Chỉ cần một đoán, nhưng không Học Kỳ Mùa Xuân lọc HTTP hỗ trợ? – SJuan76

Trả lời

4

Bạn không xử lý trong Spring. Thay vào đó bạn sử dụng một bộ lọc để dữ liệu đến trong Spring đã bị xì hơi.

Hy vọng rằng hai liên kết này có thể giúp bạn bắt đầu.

+6

Câu hỏi được hỏi về yêu cầu gzip thay vì trả lời. – Happier

5

này nên được xử lý bởi các máy chủ, không phải là ứng dụng.

Theo như tôi biết, Tomcat không hỗ trợ nó, mặc dù bạn có thể có thể viết một bộ lọc.

Một cách phổ biến để xử lý việc này là đặt Tomcat (hoặc bất kỳ vùng chứa Java nào bạn đang sử dụng) phía sau máy chủ Apache được cấu hình để xử lý các đối tượng yêu cầu đã nén.

+0

như sau: https://serverfault.com/questions/56700/is-it-possible-to-enable-http-compression-for-requests#answer-56707 – Adam

+0

Nếu ví dụ bạn muốn giải nén để ghi nhật ký thông điệp? Trường hợp đó phải được xử lý bởi ứng dụng ... – megalucio

13

Bạn cần phải viết bộ lọc của riêng mình để giải nén phần thân yêu cầu đã được nén. Sine bạn sẽ đọc toàn bộ luồng đầu vào từ yêu cầu, bạn cũng cần phải ghi đè lên các tham số parcing. Đây là bộ lọc tôi đang sử dụng trong mã của mình. Chỉ hỗ trợ các yêu cầu POST đã được nén, nhưng bạn có thể cập nhật nó để sử dụng các loại yêu cầu khác nếu cần. Cũng hãy cẩn thận để phân tích các thông số Tôi đang sử dụng thư viện ổi, bạn có thể lấy của bạn từ đây: http://central.maven.org/maven2/com/google/guava/guava/

public class GzipBodyDecompressFilter extends Filter { 

@Override 
public void init(FilterConfig filterConfig) throws ServletException { 

} 
/** 
* Analyzes servlet request for possible gzipped body. 
* When Content-Encoding header has "gzip" value and request method is POST we read all the 
* gzipped stream and is it haz any data unzip it. In case when gzip Content-Encoding header 
* specified but body is not actually in gzip format we will throw ZipException. 
* 
* @param servletRequest servlet request 
* @param servletResponse servlet response 
* @param chain   filter chain 
* @throws IOException  throws when fails 
* @throws ServletException thrown when fails 
*/ 
@Override 
public final void doFilter(final ServletRequest servletRequest, 
          final ServletResponse servletResponse, 
          final FilterChain chain) throws IOException, ServletException { 
    HttpServletRequest request = (HttpServletRequest) servletRequest; 
    HttpServletResponse response = (HttpServletResponse) servletResponse; 
    boolean isGzipped = request.getHeader(HttpHeaders.CONTENT_ENCODING) != null 
      && request.getHeader(HttpHeaders.CONTENT_ENCODING).contains("gzip"); 
    boolean requestTypeSupported = HttpMethods.POST.equals(request.getMethod()); 
    if (isGzipped && !requestTypeSupported) { 
     throw new IllegalStateException(request.getMethod() 
       + " is not supports gzipped body of parameters." 
       + " Only POST requests are currently supported."); 
    } 
    if (isGzipped && requestTypeSupported) { 
     request = new GzippedInputStreamWrapper((HttpServletRequest) servletRequest); 
    } 
    chain.doFilter(request, response); 

} 

/** 
* @inheritDoc 
*/ 
@Override 
public final void destroy() { 
} 

/** 
* Wrapper class that detects if the request is gzipped and ungzipps it. 
*/ 
final class GzippedInputStreamWrapper extends HttpServletRequestWrapper { 
    /** 
    * Default encoding that is used when post parameters are parsed. 
    */ 
    public static final String DEFAULT_ENCODING = "ISO-8859-1"; 

    /** 
    * Serialized bytes array that is a result of unzipping gzipped body. 
    */ 
    private byte[] bytes; 

    /** 
    * Constructs a request object wrapping the given request. 
    * In case if Content-Encoding contains "gzip" we wrap the input stream into byte array 
    * to original input stream has nothing in it but hew wrapped input stream always returns 
    * reproducible ungzipped input stream. 
    * 
    * @param request request which input stream will be wrapped. 
    * @throws java.io.IOException when input stream reqtieval failed. 
    */ 
    public GzippedInputStreamWrapper(final HttpServletRequest request) throws IOException { 
     super(request); 
     try { 
      final InputStream in = new GZIPInputStream(request.getInputStream()); 
      bytes = ByteStreams.toByteArray(in); 
     } catch (EOFException e) { 
      bytes = new byte[0]; 
     } 
    } 


    /** 
    * @return reproduceable input stream that is either equal to initial servlet input 
    * stream(if it was not zipped) or returns unzipped input stream. 
    * @throws IOException if fails. 
    */ 
    @Override 
    public ServletInputStream getInputStream() throws IOException { 
     final ByteArrayInputStream sourceStream = new ByteArrayInputStream(bytes); 
     return new ServletInputStream() { 
      public int read() throws IOException { 
       return sourceStream.read(); 
      } 

      public void close() throws IOException { 
       super.close(); 
       sourceStream.close(); 
      } 
     }; 
    } 

    /** 
    * Need to override getParametersMap because we initially read the whole input stream and 
    * servlet container won't have access to the input stream data. 
    * 
    * @return parsed parameters list. Parameters get parsed only when Content-Type 
    * "application/x-www-form-urlencoded" is set. 
    */ 
    @Override 
    public Map getParameterMap() { 
     String contentEncodingHeader = getHeader(HttpHeaders.CONTENT_TYPE); 
     if (!Strings.isNullOrEmpty(contentEncodingHeader) 
       && contentEncodingHeader.contains("application/x-www-form-urlencoded")) { 
      Map params = new HashMap(super.getParameterMap()); 
      try { 
       params.putAll(parseParams(new String(bytes))); 
      } catch (UnsupportedEncodingException e) { 
       e.printStackTrace(); 
      } 
      return params; 
     } else { 
      return super.getParameterMap(); 
     } 
    } 

    /** 
    * parses params from the byte input stream. 
    * 
    * @param body request body serialized to string. 
    * @return parsed parameters map. 
    * @throws UnsupportedEncodingException if encoding provided is not supported. 
    */ 
    private Map<String, String[]> parseParams(final String body) 
      throws UnsupportedEncodingException { 
     String characterEncoding = getCharacterEncoding(); 
     if (null == characterEncoding) { 
      characterEncoding = DEFAULT_ENCODING; 
     } 
     final Multimap<String, String> parameters = ArrayListMultimap.create(); 
     for (String pair : body.split("&")) { 
      if (Strings.isNullOrEmpty(pair)) { 
       continue; 
      } 
      int idx = pair.indexOf("="); 

      String key = null; 
      if (idx > 0) { 
       key = URLDecoder.decode(pair.substring(0, idx), characterEncoding); 
      } else { 
       key = pair; 
      } 
      String value = null; 
      if (idx > 0 && pair.length() > idx + 1) { 
       value = URLDecoder.decode(pair.substring(idx + 1), characterEncoding); 
      } else { 
       value = null; 
      } 
      parameters.put(key, value); 
     } 
     return Maps.transformValues(parameters.asMap(), 
       new Function<Collection<String>, String[]>() { 
        @Nullable 
        @Override 
        public String[] apply(final Collection<String> input) { 
         return Iterables.toArray(input, String.class); 
        } 
       }); 
    } 
} 

}

Các vấn đề liên quan