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