Java HTTP Client обрабатывает сжатие

Я пытался найти упоминание об обработке сжатия в новом Java HTTP Client, но не получилось. Есть ли встроенная конфигурация для обработки, например, gzip или же deflate сжатие?

Я ожидал бы иметь BodyHandler например, что-то вроде этого:

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

но я не вижу ничего. Я не вижу никакой конфигурации в HttpClient или. Я смотрю не в том месте или это намеренно не реализовано и не отложено для поддержки библиотек?

1 ответ

Решение

Нет, сжатие gzip/deflate по умолчанию не обрабатывается. Вы должны будете реализовать это в своем коде приложения, если вам это нужно - например, предоставляя BodySubscriber справиться с этим. В качестве альтернативы - вы можете посмотреть, предлагают ли некоторые из библиотек реактивных потоков такую ​​функцию, и в этом случае вы можете передать это с помощью одного из BodyHandlers.fromSubscriber​(Flow.Subscriber<? super List<ByteBuffer>> subscriber) или же BodyHandlers.ofPublisher() методы.

Я также был удивлен, что новый java.net.http Framework не обрабатывает это автоматически, но следующее работает для меня, чтобы обработать ответы HTTP, которые получены как InputStream и либо распакованы, либо сжаты с помощью 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", тем больше беспорядка это звучало). Но я полагаю, что вы можете легко поддерживать "deflate", добавив проверку к вышеуказанному блоку переключателей и обернув httpResponse.body() в InflaterInputStream,

Этот вопрос немного устарел, но я недавно выпустил библиотеку, которая исправляет эту проблему. Библиотека называется Methanol и доступна на Maven.

Вы можете использовать его для декодирования ответа следующим образом:

HttpResponse<String> response = client.send(request, MoreBodyHandlers.decoding(BodyHandlers.ofString()));

Вы также можете использовать любой BodyHandler вы хотите. MoreBodyHandlers::decodingВашему обработчику кажется, что ответ никогда не был сжат! Он заботится оContent-Encodingзаголовок и все. По умолчанию поддерживаются Gzip и deflate, также есть модуль для brotli.

Еще лучше, вы можете использовать пользовательский HttpClient для прозрачного сжатия (не нужно добавлять Accept-Encoding):

Methanol client = Methanol.newBuilder()
    .autoAcceptEncoding(true) // note that true is the default
    .build();
HttpRequest request = ...
HttpResponse<String> response = client.send(request, BodyHandlers.ofString()); // response is compressed transparently
Другие вопросы по тегам