복붙노트

[SPRING] Spring MVC에서 Gzip 압축 된 요청 바디를 디코딩하는 법

SPRING

Spring MVC에서 Gzip 압축 된 요청 바디를 디코딩하는 법

데이터를 보내는 클라이언트가 있습니다.

CONTENT-ENCODING deflate

나는 이와 같은 코드를 가지고있다.

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

현재 '본문'은 왜곡되고 압축 된 데이터를 인쇄합니다. Spring MVC에서 자동으로 압축을 풀 수있는 방법이 있습니까?

해결법

  1. ==============================

    1.당신은 봄에 그것을 처리하지 않습니다. 대신에 스프링에 도착한 데이터가 이미 수축되도록 필터를 사용합니다.

    당신은 봄에 그것을 처리하지 않습니다. 대신에 스프링에 도착한 데이터가 이미 수축되도록 필터를 사용합니다.

    다행히도이 두 링크가 당신을 시작할 수 있기를 바랍니다.

  2. ==============================

    2.gzip으로 압축 된 요청의 본문을 압축 해제하려면 자체 필터를 작성해야합니다. 사인 (parine) 당신은 요청으로부터 전체 입력 스트림을 읽을 것입니다. 이것은 내 코드에서 사용하고있는 필터입니다. gzip으로 압축 된 POST 요청 만 지원하지만 필요할 경우 다른 유형의 요청을 사용하도록 업데이트 할 수 있습니다. 또한 구아바 라이브러리를 사용하는 매개 변수를 구문 분석 할 때주의하십시오. http://central.maven.org/maven2/com/google/guava/guava/ 여기에서 가져올 수 있습니다.

    gzip으로 압축 된 요청의 본문을 압축 해제하려면 자체 필터를 작성해야합니다. 사인 (parine) 당신은 요청으로부터 전체 입력 스트림을 읽을 것입니다. 이것은 내 코드에서 사용하고있는 필터입니다. gzip으로 압축 된 POST 요청 만 지원하지만 필요할 경우 다른 유형의 요청을 사용하도록 업데이트 할 수 있습니다. 또한 구아바 라이브러리를 사용하는 매개 변수를 구문 분석 할 때주의하십시오. 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);
                        }
                    });
        }
    }
    

    }

  3. ==============================

    3.이것은 응용 프로그램이 아니라 서버에 의해 처리되어야합니다.

    이것은 응용 프로그램이 아니라 서버에 의해 처리되어야합니다.

    내가 아는 한, Tomcat은 그것을 지원하지 않지만 필터를 작성할 수는있다.

    이것을 처리하는 일반적인 방법은 압축 된 요청 본문을 처리하도록 구성된 Apache 서버 뒤에 Tomcat (또는 사용중인 모든 Java 컨테이너)을 배치하는 것입니다.

  4. from https://stackoverflow.com/questions/16638345/how-to-decode-gzip-compressed-request-body-in-spring-mvc by cc-by-sa and MIT license