库 Apache Commons HttpClient 是否支持 Gzip?我们想在我们的 Apache 服务器上使用启用 gzip 压缩来加速客户端/服务器通信(我们有一个 php 页面,允许我们的 Android 应用程序与服务器同步文件)。
8 回答
Apache HttpClient 4.1 支持开箱即用的内容压缩以及以前被认为超出范围的许多其他功能。
如果您的服务器能够提供 GZIPped 内容,那么您只需使用 Apache Http 客户端 4.1
org.apache.http.impl.client.ContentEncodingHttpClient
它是 的子类DefaultHttpClient
。
该客户端还将添加标头,说明它接受 GZIPped 内容。
从 4.1 开始,Apache HttpClients 处理请求和响应压缩。
- 您无需压缩请求,无需在请求标头中设置任何“Accept-Encoding”。
- 它也会自动处理响应解压,无需处理响应解压。
- 直到 4.3 它处理 gzip 和 deflate。您可以在此处
ResponseContentEncoding
查看api 文档。
只需使用:
HttpClients.custom()
它使用:
HttpClientBuilder.create()
如果你想签入库 gotoHttpClientBuilder
它使用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();
它不支持这种开箱即用的功能,而且似乎不太可能将其添加到 HttpClient 3.x 中(请参阅此处相当讨厌的 JIRA 问题)。但是,您可以通过添加自定义请求阅读器和手动请求/响应流处理来做到这一点,分层在基本库之上,但这很繁琐。
看来您可以使用 HttpClient 4 来做到这一点,但并非不费吹灰之力。
相当粗制滥造,如果你问我,这东西真的应该比它更容易。
这是使用 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()
}
它不支持开箱即用,但您可以HttpResponse
通过调用将返回的实体转换为未压缩的实体
val entity = new GzipDecompressingEntity(response.getEntity)
然后entity.getContent
像往常一样继续。
对于那些(像我一样)由于其他原因无法更新到 Apache 4.xx 并且需要拥有他们的 Apache 的人(顺便说一下,下面的 4.3.6 版本首先实现了它显然不支持“开箱即用”,尽管这可能是当然,因为我们总是使用对我们的 httpclients 有其他特定要求的自定义客户端 [“开箱即用”当然可以,如果您完全了解最新信息并且可以接受这个概念的实际含义 - 例如默认重试策略,SSL 主机名验证,默认超时等对我们不起作用- 如果您使用自定义,则必须了解你在做什么,从长远来看,这总是更好的......?])。无论如何,该解决方案也适用于 4.xx 之前的版本——我在上面 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();
所以 - 这些的接受标头将始终添加到传出请求中,并且压缩响应由响应拦截器处理。工作正常。
自定义协议拦截器也可能有所帮助。
免责声明:我还没有尝试过。