如何在JavaServlet中处理压缩(gzip)HTTP请求(而不是响应)-简单示例?

如何在JavaServlet中处理压缩(gzip)HTTP请求(而不是响应)-简单示例?,java,servlets,compression,httprequest,gzip,Java,Servlets,Compression,Httprequest,Gzip,我与这个问题斗争了很长一段时间;在找到一个简单的解决方案之后。。。想问一个问题和答案 在堆栈溢出问题上,已多次以不同的方式提出该问题,公认的解决方案要么是部分正确且复杂,要么是谈论响应压缩 汇总一些关于此主题的旧问答: <filter> <filter-name>GzipRequestFilter</filter-name> <filter-class>com...pkg...GzipRequestFilter</filter

我与这个问题斗争了很长一段时间;在找到一个简单的解决方案之后。。。想问一个问题和答案

在堆栈溢出问题上,已多次以不同的方式提出该问题,
公认的解决方案
要么是
部分正确且复杂
,要么是谈论
响应
压缩

汇总一些关于此主题的旧问答:

<filter>
    <filter-name>GzipRequestFilter</filter-name>
    <filter-class>com...pkg...GzipRequestFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>GzipRequestFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
public class GzipRequestFilter implements Filter {
    // Optional but recommended.
    private static final Set<String> METHODS_TO_IGNORE = ImmutableSet.of("GET", "OPTIONS", "HEAD");

    @Override
    public void doFilter(
            final ServletRequest request,
            final ServletResponse response,
            final FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        
        String method = httpServletRequest.getMethod().toUpperCase();
        String encoding = Strings.nullToEmpty(
            httpServletRequest.getHeader(HttpHeaders.CONTENT_ENCODING));

        if (METHODS_TO_IGNORE.contains(method) || !encoding.contains("application/gzip")) {
            chain.doFilter(request, response); // pass through
            return;
        }
        
        HttpServletRequestWrapper requestInflated = new GzippedInputStreamWrapper(httpServletRequest);
        chain.doFilter(requestInflated, response);
    }

    @Override
    public void init(final FilterConfig filterConfig) throws ServletException {}
    @Override
    public void destroy() {}
}
// Simple Wrapper class to inflate body of a gzipped HttpServletRequest.
final class GzippedInputStreamWrapper extends HttpServletRequestWrapper {
    private GZIPInputStream inputStream;

    GzippedInputStreamWrapper(final HttpServletRequest request) throws IOException {
        super(request);
        inputStream = new GZIPInputStream(request.getInputStream());
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return new ServletInputStream() {
            // NOTE: Later versions of javax.servlet library may require more overrides.
            public int read() throws IOException {
                return inputStream.read();
            }
            public void close() throws IOException {
                super.close();
                inputStream.close();
            }
        };
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(inputStream));
    }
}
  • 接受的ans错误/部分正确且复杂 后续ans

    • :(第二个ans几乎正确,但复杂的杀伤力过大)
  • 被接受的ans是错误的。它是关于
    响应
    压缩,而不是
    请求

  • 类似问题-终止于“无请求压缩”

  • Spring RestTemplate框架的一个特定问题&ans:


    • 一个简单的解决方案是使用过滤器。()

      创建Servlet筛选器:

      <filter>
          <filter-name>GzipRequestFilter</filter-name>
          <filter-class>com...pkg...GzipRequestFilter</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>GzipRequestFilter</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
      
      public class GzipRequestFilter implements Filter {
          // Optional but recommended.
          private static final Set<String> METHODS_TO_IGNORE = ImmutableSet.of("GET", "OPTIONS", "HEAD");
      
          @Override
          public void doFilter(
                  final ServletRequest request,
                  final ServletResponse response,
                  final FilterChain chain) throws IOException, ServletException {
              HttpServletRequest httpServletRequest = (HttpServletRequest) request;
              
              String method = httpServletRequest.getMethod().toUpperCase();
              String encoding = Strings.nullToEmpty(
                  httpServletRequest.getHeader(HttpHeaders.CONTENT_ENCODING));
      
              if (METHODS_TO_IGNORE.contains(method) || !encoding.contains("application/gzip")) {
                  chain.doFilter(request, response); // pass through
                  return;
              }
              
              HttpServletRequestWrapper requestInflated = new GzippedInputStreamWrapper(httpServletRequest);
              chain.doFilter(requestInflated, response);
          }
      
          @Override
          public void init(final FilterConfig filterConfig) throws ServletException {}
          @Override
          public void destroy() {}
      }
      
      // Simple Wrapper class to inflate body of a gzipped HttpServletRequest.
      final class GzippedInputStreamWrapper extends HttpServletRequestWrapper {
          private GZIPInputStream inputStream;
      
          GzippedInputStreamWrapper(final HttpServletRequest request) throws IOException {
              super(request);
              inputStream = new GZIPInputStream(request.getInputStream());
          }
      
          @Override
          public ServletInputStream getInputStream() throws IOException {
              return new ServletInputStream() {
                  // NOTE: Later versions of javax.servlet library may require more overrides.
                  public int read() throws IOException {
                      return inputStream.read();
                  }
                  public void close() throws IOException {
                      super.close();
                      inputStream.close();
                  }
              };
          }
      
          @Override
          public BufferedReader getReader() throws IOException {
              return new BufferedReader(new InputStreamReader(inputStream));
          }
      }
      
      • 确保在使用请求正文的任何筛选器之前/之前调用筛选器
      I.在web.xml中注册过滤器:

      <filter>
          <filter-name>GzipRequestFilter</filter-name>
          <filter-class>com...pkg...GzipRequestFilter</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>GzipRequestFilter</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
      
      public class GzipRequestFilter implements Filter {
          // Optional but recommended.
          private static final Set<String> METHODS_TO_IGNORE = ImmutableSet.of("GET", "OPTIONS", "HEAD");
      
          @Override
          public void doFilter(
                  final ServletRequest request,
                  final ServletResponse response,
                  final FilterChain chain) throws IOException, ServletException {
              HttpServletRequest httpServletRequest = (HttpServletRequest) request;
              
              String method = httpServletRequest.getMethod().toUpperCase();
              String encoding = Strings.nullToEmpty(
                  httpServletRequest.getHeader(HttpHeaders.CONTENT_ENCODING));
      
              if (METHODS_TO_IGNORE.contains(method) || !encoding.contains("application/gzip")) {
                  chain.doFilter(request, response); // pass through
                  return;
              }
              
              HttpServletRequestWrapper requestInflated = new GzippedInputStreamWrapper(httpServletRequest);
              chain.doFilter(requestInflated, response);
          }
      
          @Override
          public void init(final FilterConfig filterConfig) throws ServletException {}
          @Override
          public void destroy() {}
      }
      
      // Simple Wrapper class to inflate body of a gzipped HttpServletRequest.
      final class GzippedInputStreamWrapper extends HttpServletRequestWrapper {
          private GZIPInputStream inputStream;
      
          GzippedInputStreamWrapper(final HttpServletRequest request) throws IOException {
              super(request);
              inputStream = new GZIPInputStream(request.getInputStream());
          }
      
          @Override
          public ServletInputStream getInputStream() throws IOException {
              return new ServletInputStream() {
                  // NOTE: Later versions of javax.servlet library may require more overrides.
                  public int read() throws IOException {
                      return inputStream.read();
                  }
                  public void close() throws IOException {
                      super.close();
                      inputStream.close();
                  }
              };
          }
      
          @Override
          public BufferedReader getReader() throws IOException {
              return new BufferedReader(new InputStreamReader(inputStream));
          }
      }
      

      现在剩下的是如何发送压缩请求

      邮递员还不支持发送压缩的
      HttpRequest
      正文。您仍然可以通过使用
      binary
      选项并使用包含正确编码的请求正文的gzip文件使其工作

      一种方法是使用带有
      pako
      的nodejs脚本。有关多部分/表单数据请求,请参见
      表单数据


      注意事项:

      <filter>
          <filter-name>GzipRequestFilter</filter-name>
          <filter-class>com...pkg...GzipRequestFilter</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>GzipRequestFilter</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
      
      public class GzipRequestFilter implements Filter {
          // Optional but recommended.
          private static final Set<String> METHODS_TO_IGNORE = ImmutableSet.of("GET", "OPTIONS", "HEAD");
      
          @Override
          public void doFilter(
                  final ServletRequest request,
                  final ServletResponse response,
                  final FilterChain chain) throws IOException, ServletException {
              HttpServletRequest httpServletRequest = (HttpServletRequest) request;
              
              String method = httpServletRequest.getMethod().toUpperCase();
              String encoding = Strings.nullToEmpty(
                  httpServletRequest.getHeader(HttpHeaders.CONTENT_ENCODING));
      
              if (METHODS_TO_IGNORE.contains(method) || !encoding.contains("application/gzip")) {
                  chain.doFilter(request, response); // pass through
                  return;
              }
              
              HttpServletRequestWrapper requestInflated = new GzippedInputStreamWrapper(httpServletRequest);
              chain.doFilter(requestInflated, response);
          }
      
          @Override
          public void init(final FilterConfig filterConfig) throws ServletException {}
          @Override
          public void destroy() {}
      }
      
      // Simple Wrapper class to inflate body of a gzipped HttpServletRequest.
      final class GzippedInputStreamWrapper extends HttpServletRequestWrapper {
          private GZIPInputStream inputStream;
      
          GzippedInputStreamWrapper(final HttpServletRequest request) throws IOException {
              super(request);
              inputStream = new GZIPInputStream(request.getInputStream());
          }
      
          @Override
          public ServletInputStream getInputStream() throws IOException {
              return new ServletInputStream() {
                  // NOTE: Later versions of javax.servlet library may require more overrides.
                  public int read() throws IOException {
                      return inputStream.read();
                  }
                  public void close() throws IOException {
                      super.close();
                      inputStream.close();
                  }
              };
          }
      
          @Override
          public BufferedReader getReader() throws IOException {
              return new BufferedReader(new InputStreamReader(inputStream));
          }
      }
      
      • 我们使用
        Content-Encoding:application/gzip
        头指定压缩请求。是的,这是标准的
      • 不要使用
        内容类型
        ,因为它不适用于
        多部分/表单数据
      • HTTP协议一直是在这样的假设下运行的,即HttpRequests的大小比HttpResponse的小
      • 此外,由于假定浏览器/客户端的计算能力有限,标准是压缩响应而不是请求。浏览器不能进行本机压缩,但可以进行本机解压缩
      • 但是,不幸的是,经过多年的开发人员推动代码;一些HTTP API会演变为使用大型字符串/数据
      • 允许Javaservlet使用压缩请求是小菜一碟

        • 一个简单的解决方案是使用过滤器。()

          创建Servlet筛选器:

          <filter>
              <filter-name>GzipRequestFilter</filter-name>
              <filter-class>com...pkg...GzipRequestFilter</filter-class>
          </filter>
          <filter-mapping>
              <filter-name>GzipRequestFilter</filter-name>
              <url-pattern>/*</url-pattern>
          </filter-mapping>
          
          public class GzipRequestFilter implements Filter {
              // Optional but recommended.
              private static final Set<String> METHODS_TO_IGNORE = ImmutableSet.of("GET", "OPTIONS", "HEAD");
          
              @Override
              public void doFilter(
                      final ServletRequest request,
                      final ServletResponse response,
                      final FilterChain chain) throws IOException, ServletException {
                  HttpServletRequest httpServletRequest = (HttpServletRequest) request;
                  
                  String method = httpServletRequest.getMethod().toUpperCase();
                  String encoding = Strings.nullToEmpty(
                      httpServletRequest.getHeader(HttpHeaders.CONTENT_ENCODING));
          
                  if (METHODS_TO_IGNORE.contains(method) || !encoding.contains("application/gzip")) {
                      chain.doFilter(request, response); // pass through
                      return;
                  }
                  
                  HttpServletRequestWrapper requestInflated = new GzippedInputStreamWrapper(httpServletRequest);
                  chain.doFilter(requestInflated, response);
              }
          
              @Override
              public void init(final FilterConfig filterConfig) throws ServletException {}
              @Override
              public void destroy() {}
          }
          
          // Simple Wrapper class to inflate body of a gzipped HttpServletRequest.
          final class GzippedInputStreamWrapper extends HttpServletRequestWrapper {
              private GZIPInputStream inputStream;
          
              GzippedInputStreamWrapper(final HttpServletRequest request) throws IOException {
                  super(request);
                  inputStream = new GZIPInputStream(request.getInputStream());
              }
          
              @Override
              public ServletInputStream getInputStream() throws IOException {
                  return new ServletInputStream() {
                      // NOTE: Later versions of javax.servlet library may require more overrides.
                      public int read() throws IOException {
                          return inputStream.read();
                      }
                      public void close() throws IOException {
                          super.close();
                          inputStream.close();
                      }
                  };
              }
          
              @Override
              public BufferedReader getReader() throws IOException {
                  return new BufferedReader(new InputStreamReader(inputStream));
              }
          }
          
          • 确保在使用请求正文的任何筛选器之前/之前调用筛选器
          I.在web.xml中注册过滤器:

          <filter>
              <filter-name>GzipRequestFilter</filter-name>
              <filter-class>com...pkg...GzipRequestFilter</filter-class>
          </filter>
          <filter-mapping>
              <filter-name>GzipRequestFilter</filter-name>
              <url-pattern>/*</url-pattern>
          </filter-mapping>
          
          public class GzipRequestFilter implements Filter {
              // Optional but recommended.
              private static final Set<String> METHODS_TO_IGNORE = ImmutableSet.of("GET", "OPTIONS", "HEAD");
          
              @Override
              public void doFilter(
                      final ServletRequest request,
                      final ServletResponse response,
                      final FilterChain chain) throws IOException, ServletException {
                  HttpServletRequest httpServletRequest = (HttpServletRequest) request;
                  
                  String method = httpServletRequest.getMethod().toUpperCase();
                  String encoding = Strings.nullToEmpty(
                      httpServletRequest.getHeader(HttpHeaders.CONTENT_ENCODING));
          
                  if (METHODS_TO_IGNORE.contains(method) || !encoding.contains("application/gzip")) {
                      chain.doFilter(request, response); // pass through
                      return;
                  }
                  
                  HttpServletRequestWrapper requestInflated = new GzippedInputStreamWrapper(httpServletRequest);
                  chain.doFilter(requestInflated, response);
              }
          
              @Override
              public void init(final FilterConfig filterConfig) throws ServletException {}
              @Override
              public void destroy() {}
          }
          
          // Simple Wrapper class to inflate body of a gzipped HttpServletRequest.
          final class GzippedInputStreamWrapper extends HttpServletRequestWrapper {
              private GZIPInputStream inputStream;
          
              GzippedInputStreamWrapper(final HttpServletRequest request) throws IOException {
                  super(request);
                  inputStream = new GZIPInputStream(request.getInputStream());
              }
          
              @Override
              public ServletInputStream getInputStream() throws IOException {
                  return new ServletInputStream() {
                      // NOTE: Later versions of javax.servlet library may require more overrides.
                      public int read() throws IOException {
                          return inputStream.read();
                      }
                      public void close() throws IOException {
                          super.close();
                          inputStream.close();
                      }
                  };
              }
          
              @Override
              public BufferedReader getReader() throws IOException {
                  return new BufferedReader(new InputStreamReader(inputStream));
              }
          }
          

          现在剩下的是如何发送压缩请求

          邮递员还不支持发送压缩的
          HttpRequest
          正文。您仍然可以通过使用
          binary
          选项并使用包含正确编码的请求正文的gzip文件使其工作

          一种方法是使用带有
          pako
          的nodejs脚本。有关多部分/表单数据请求,请参见
          表单数据


          注意事项:

          <filter>
              <filter-name>GzipRequestFilter</filter-name>
              <filter-class>com...pkg...GzipRequestFilter</filter-class>
          </filter>
          <filter-mapping>
              <filter-name>GzipRequestFilter</filter-name>
              <url-pattern>/*</url-pattern>
          </filter-mapping>
          
          public class GzipRequestFilter implements Filter {
              // Optional but recommended.
              private static final Set<String> METHODS_TO_IGNORE = ImmutableSet.of("GET", "OPTIONS", "HEAD");
          
              @Override
              public void doFilter(
                      final ServletRequest request,
                      final ServletResponse response,
                      final FilterChain chain) throws IOException, ServletException {
                  HttpServletRequest httpServletRequest = (HttpServletRequest) request;
                  
                  String method = httpServletRequest.getMethod().toUpperCase();
                  String encoding = Strings.nullToEmpty(
                      httpServletRequest.getHeader(HttpHeaders.CONTENT_ENCODING));
          
                  if (METHODS_TO_IGNORE.contains(method) || !encoding.contains("application/gzip")) {
                      chain.doFilter(request, response); // pass through
                      return;
                  }
                  
                  HttpServletRequestWrapper requestInflated = new GzippedInputStreamWrapper(httpServletRequest);
                  chain.doFilter(requestInflated, response);
              }
          
              @Override
              public void init(final FilterConfig filterConfig) throws ServletException {}
              @Override
              public void destroy() {}
          }
          
          // Simple Wrapper class to inflate body of a gzipped HttpServletRequest.
          final class GzippedInputStreamWrapper extends HttpServletRequestWrapper {
              private GZIPInputStream inputStream;
          
              GzippedInputStreamWrapper(final HttpServletRequest request) throws IOException {
                  super(request);
                  inputStream = new GZIPInputStream(request.getInputStream());
              }
          
              @Override
              public ServletInputStream getInputStream() throws IOException {
                  return new ServletInputStream() {
                      // NOTE: Later versions of javax.servlet library may require more overrides.
                      public int read() throws IOException {
                          return inputStream.read();
                      }
                      public void close() throws IOException {
                          super.close();
                          inputStream.close();
                      }
                  };
              }
          
              @Override
              public BufferedReader getReader() throws IOException {
                  return new BufferedReader(new InputStreamReader(inputStream));
              }
          }
          
          • 我们使用
            Content-Encoding:application/gzip
            头指定压缩请求。是的,这是标准的
          • 不要使用
            内容类型
            ,因为它不适用于
            多部分/表单数据
          • HTTP协议一直是在这样的假设下运行的,即HttpRequests的大小比HttpResponse的小
          • 此外,由于假定浏览器/客户端的计算能力有限,标准是压缩响应而不是请求。浏览器不能进行本机压缩,但可以进行本机解压缩
          • 但是,不幸的是,经过多年的开发人员推动代码;一些HTTP API会演变为使用大型字符串/数据
          • 允许Javaservlet使用压缩请求是小菜一碟
          有一份规范草案。也许有一天它会被接受为推荐。这里有一份规范草案。也许有一天它会被接受为推荐