Java HTTP 客户端是否处理压缩

Does Java HTTP Client handle compression

我试图在新的 Java HTTP 客户端中找到关于压缩处理的任何提及,但失败了。是否有内置配置来处理例如gzipdeflate 压缩?

我希望有一个 BodyHandler 例如像这样:

HttpResponse.BodyHandlers.ofGzipped(HttpResponse.BodyHandlers.ofString())

但我没看到。我也没有在 HttpClient 中看到任何配置。我是不是找错地方了,或者这是故意没有实现并推迟到支持库?

否,gzip/deflate 默认情况下不处理压缩。如果需要,您必须在应用程序代码中实现它——例如通过提供自定义的 BodySubscriber 来处理它。或者 - 您可能想看看那里的一些反应流库是否提供这样的功能,在这种情况下,您可以使用 BodyHandlers.fromSubscriber​(Flow.Subscriber<? super List<ByteBuffer>> subscriber)BodyHandlers.ofPublisher() 方法。

我也很惊讶新的 java.net.http 框架没有自动处理这个问题,但下面的内容对我来说可以处理以 InputStream 形式接收的 HTTP 响应,这些响应要么是未压缩的,要么是用 gzip 压缩:

public static InputStream getDecodedInputStream(
        HttpResponse<InputStream> httpResponse) {
    String encoding = determineContentEncoding(httpResponse);
    try {
        switch (encoding) {
            case "":
                return httpResponse.body();
            case "gzip":
                return new GZIPInputStream(httpResponse.body());
            default:
                throw new UnsupportedOperationException(
                        "Unexpected Content-Encoding: " + encoding);
        }
    } catch (IOException ioe) {
        throw new UncheckedIOException(ioe);
    }
}

public static String determineContentEncoding(
        HttpResponse<?> httpResponse) {
    return httpResponse.headers().firstValue("Content-Encoding").orElse("");
}

请注意,我没有添加对 "deflate" 类型的支持(因为我目前不需要它,而且我对 "deflate" 的了解越多,听起来越乱) .但我相信您可以通过向上面的开关块添加检查并将 httpResponse.body() 包装在 InflaterInputStream.

中来轻松支持 "deflate"

您可以对 brotli 使用 Methanol. It has decompressing BodyHandler implementations, with out-of-the-box support for gzip & deflate. There's also a module

var response = client.send(request, MoreBodyHandlers.decoding(BodyHandlers.ofString()));

请注意,您可以使用任何 BodyHandlerMoreBodyHandlers::decoding 让您的处理程序看起来好像响应从未被压缩过!它负责 Content-Encoding header 和所有

更好的是,您可以使用 Methanol 自己的 HttpClient,它会在您的请求中添加适当的 Accept-Encoding 后进行透明解压。

var client = Methanol.create();
var request = MutableRequest.GET("https://example.com");
var response = client.send(request, BodyHandlers.ofString()); // The response is transparently decompressed