【问题标题】:Does Apache Commons HttpClient support GZIP?Apache Commons HttpClient 是否支持 GZIP?
【发布时间】:2011-02-16 03:38:15
【问题描述】:

库 Apache Commons HttpClient 是否支持 Gzip?我们想在我们的 Apache 服务器上使用启用 gzip 压缩来加速客户端/服务器通信(我们有一个 php 页面,允许我们的 Android 应用程序与服务器同步文件)。

【问题讨论】:

    标签: java gzip apache-commons apache-httpclient-4.x apache-commons-httpclient


    【解决方案1】:

    它不支持这种开箱即用的功能,而且似乎不太可能将其添加到 HttpClient 3.x 中(请参阅相当讨厌的 JIRA 问题here)。但是,您可以通过添加自定义请求阅读器和手动请求/响应流处理来实现这一点,分层在基本库之上,但这很繁琐。

    您似乎可以使用 HttpClient 4 来做到这一点,但并非不费吹灰之力。

    相当粗制滥造,如果你问我,这东西真的应该比它更容易。

    【讨论】:

    • @karim79:我已经放弃了 HttpClient 由任何掌握现实的人维护的希望(好像 HttpClient 4 API 没有足够的证据)。
    【解决方案2】:

    Apache HttpClient 4.1 支持开箱即用的内容压缩以及许多以前被认为超出范围的其他功能。

    【讨论】:

    • 如何将其从盒子中取出?
    • 在 4.5.3 中,只需通过 HttpClientBuilder.create().build() 使用客户端,它将为您处理所有 gzip 请求和响应解压。
    【解决方案3】:

    如果您的服务器能够提供 GZIPped 内容,那么您只需使用 Apache Http 客户端 4.1 即可

    org.apache.http.impl.client.ContentEncodingHttpClient
    

    这是DefaultHttpClient的子类。

    此客户端还将添加标头,表明它接受 GZIPped 内容。

    【讨论】:

    • 在 HttpClient 4.2.1 中,ContentEncodingHttpClient 已被弃用;鼓励用户使用 DecompressingHttpClient,见hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/…
    • @Hbf 也已弃用。
    • 从 4.3 开始,应该使用HttpClientBuilder(而不是ContentEncodingHttpClientDecompressingHttpClient)。
    • 使用HttpClientBuilder,您是否必须调用构建器上的任何特定方法才能启用gzip?还是您根本不必打电话给disableContentCompression()
    • 不,压缩是自动启用的。我用4.5.3试了一下,用wireshark抓取请求响应:请求中自动添加了“Accept-Encoding: gzip,deflate”头,可以自动解压响应内容。
    【解决方案4】:

    Custom Protocol Interceptors 也可能有帮助。

    免责声明:我还没有尝试过。

    【讨论】:

      【解决方案5】:

      它不支持开箱即用,但您可以通过调用将返回的HttpResponse 的实体转换为未压缩的实体

      val entity = new GzipDecompressingEntity(response.getEntity)
      

      然后像往常一样继续使用entity.getContent

      【讨论】:

        【解决方案6】:

        这是使用 java apache-http-client 库的示例 scala 代码

         def createCloseableHttpClient(): CloseableHttpClient = {
            val builder: HttpClientBuilder = HttpClientBuilder.create
            val closableClient = builder.build()
            closableClient
          }
        
          def postData(data: String): Unit = {
            val entity = EntityBuilder.create()
              .setText(data)
              .setContentType(ContentType.TEXT_PLAIN)
              .gzipCompress()
              .build()
            val post = new HttpPost(postURL + endPoint)
            post.setEntity(entity)
            post.setHeader("Content-Type", "application/gzip")
            val client = createCloseableHttpClient()
            client.execute(post)
            client.close()
          }
        

        【讨论】:

          【解决方案7】:

          自 4.1 起,Apache HttpClients 处理请求和响应压缩。

          • 您无需压缩请求,无需在请求标头中设置任何“Accept-Encoding”。
          • 它也会自动处理响应解压,无需处理响应解压。
          • 到 4.3 为止,它可以处理 gzip 和 deflate。您可以查看ResponseContentEncoding api doc here

          只需使用:

          HttpClients.custom()
          

          使用:

          HttpClientBuilder.create()
          

          如果你想签入库转到HttpClientBuilder,它使用RequestAcceptEncoding & ResponseContentEncoding

          您可以通过“disableContentCompression()”禁用它

          HttpClient httpClient = HttpClients.custom()
                          .setConnectionManager(cm)
                          .disableContentCompression() //this disables compression
                          .build();
          

          请确保如果您添加任何可以覆盖的拦截器,请谨慎使用。

          HttpClient httpClient = HttpClients.custom()
                          .setConnectionManager(cm)
                          .setHttpProcessor(httpprocessor) //this interceptor can override your compression.
                          .build();
          

          【讨论】:

            【解决方案8】:

            对于那些(像我一样)由于其他原因无法更新到 Apache 4.xx 并且需要拥有他们的 Apache 的人(顺便说一下,下面首先为 4.3.6 版本实现,但显然不支持“开箱即用”这可能是当然的,因为我们总是使用 custom 那些对我们的 httpclients 有其他特定要求的[“开箱即用”当然可以,如果您完全了解最新信息并且可以接受这个概念实际上会暗示 - 例如,默认重试策略、SSL 主机名验证、默认超时等对我们没有用 - 如果您改用自定义,则 必须 了解你在做什么,从长远来看,这总是更好的......?])。无论如何,该解决方案也适用于 4.x.x 之前的版本——我在上面 Garry 的良好响应之后的示例行中添加了更多内容。使用 maven 构建,并在一般情况下容纳压缩响应,我已经添加了

              <dependency>
                  <groupId>org.brotli</groupId>
                  <artifactId>dec</artifactId>
                  <version>0.1.2</version>
              </dependency>
            

            到我的 pom.xml。然后为了处理所有这三种常见的压缩方法(gzip、deflate 和 brotli),我在设置自定义 Apache HttpClient 时添加了拦截器 - 如下所示:

            private static final String GZIP = "gzip";
            private static final String DEFLATE = "deflate";
            private static final String BR = "br";
            private static final String ACCEPT_ENCODING = "Accept-Encoding";
            private static final String SUPPORTED_COMPRESSION_VARIANTS = new StringBuilder(GZIP).append(COMMA_SPACE).append(DEFLATE).append(COMMA_SPACE).append(BR).toString();
            private static final String COMMA_SPACE = ", ";
            ..
                               HttpClients.custom()..
                               .addInterceptorFirst((HttpRequestInterceptor) (request, context) -> { // add accepting compressed headers _always_
                                if (!request.containsHeader(ACCEPT_ENCODING)) {
                                    request.addHeader(ACCEPT_ENCODING, SUPPORTED_COMPRESSION_VARIANTS);
                                }
                                })
                                .addInterceptorFirst((HttpResponseInterceptor) (response, context) -> {
                                HttpEntity entity = response.getEntity();
                                Header ceheader = entity != null ? entity.getContentEncoding() : null;
                                if (ceheader != null) {
                                    HeaderElement[] codecs = ceheader.getElements();
                                    for (int i = 0; i < codecs.length; i++) {
                                        if (codecs[i].getName().equalsIgnoreCase(GZIP)) { // handling gzip
                                            response.setEntity(new GzipDecompressingEntity(response.getEntity()));
                                        } else if (codecs[i].getName().equalsIgnoreCase(DEFLATE)) { // handling deflate
                                            response.setEntity(new DeflateDecompressingEntity(response.getEntity()));
                                        } else if (codecs[i].getName().equalsIgnoreCase(BR)) { // handling brotli
                                            try (BufferedReader br =
                                                         new BufferedReader(new InputStreamReader(new BrotliInputStream(response.getEntity().getContent())))) {
                                                 response.setEntity(new StringEntity(br.lines().collect(Collectors.joining())));
                                            }
                                        }
                                    }
                                }
                              }).build();
            

            所以 - 这些的接受标头将始终添加到传出请求中,并且压缩响应由响应拦截器处理。工作正常。

            【讨论】:

              猜你喜欢
              • 2020-01-27
              • 2011-03-06
              • 1970-01-01
              • 2012-09-11
              • 2017-07-06
              • 2013-12-20
              • 2017-04-15
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多