Обертывание BodySubscriber <InputStream>в GZIPInputStream приводит к зависанию - PullRequest
0 голосов
/ 19 ноября 2018

Я использую новые классы java.net.http для обработки асинхронного обмена HTTP-запросами + ответами и пытаюсь найти способ, чтобы BodySubscriber обрабатывал различные типы кодирования, такие как gzip.

Однакоотображение BodySubsriber<InputStream> таким образом, чтобы нижележащий поток был обернут GZIPInputStream (когда в заголовке ответа найдено «Content-Encoding: gzip»), приводит к зависанию.Без исключений, только полное прекращение действия.

Код, который отображает BodySubscriber, выглядит следующим образом:

private HttpResponse.BodySubscriber<InputStream> gzippedBodySubscriber(
        HttpResponse.ResponseInfo responseInfo) {
    return HttpResponse.BodySubscribers.mapping(
            HttpResponse.BodySubscribers.ofInputStream(),
            this::decodeGzipStream);
}

private InputStream decodeGzipStream(InputStream gzippedStream) {
    System.out.println("Entered decodeGzipStream method.");
    try {
        InputStream decodedStream = new GZIPInputStream(gzippedStream);
        System.out.println(
                "Created GZIPInputStream to handle response body stream.");
        return decodedStream;
    } catch (IOException ex) {
        System.out.println("IOException occurred while trying to create GZIPInputStream.");
        throw new UncheckedIOException(ex);
    }
}

Получение ответа HTTP с кодировкой "gzip" приводит кконсоль, показывающая только это:

Введен метод EncodedBodyHandler.apply.Введен метод decodeGzipStream.

Больше ничего не видно, поэтому строка после вызова конструктора GZIPInputStream никогда не выполняется.

Кто-нибудь знает, почему эта попытка обернуть InputStream из BodySubscriber<InputStream> в GZIPInputStream висит?

Примечание: эквивалентный метод для тел без ответа (необработанный текст) HTTP-ответов содержит просто вызов BodySubscribers.ofInputStream() без сопоставления, и это позволяетответ должен быть получен и отображен без проблем.

Ответы [ 2 ]

0 голосов
/ 16 января 2019

Это действительно ошибка.Я зарегистрировался JDK-8217264 .Я могу предложить два обходных пути:

Обходной путь один

Не используйте BodySubscribers.mapping - но преобразуйте InputStream в GZIPInputStream после получения тела HttpResponse:

GZIPInputStream gzin = new GZIPInputStream(resp.getBody());

Обходной путь два

Пусть функция отображения возвращает Supplier<InputStream>, стараясь не создавать GZIPInputStream, пока Supplier::get не будет вызван

static final class ISS implements Supplier<InputStream> {
    final InputStream in;
    GZIPInputStream gz;
    ISS(InputStream in) {
        this.in = in;
    }
    public synchronized InputStream get() {
        if (gz == null) {
            try {
                gz = new GZIPInputStream(in);
            } catch (IOException t) {
                throw new UncheckedIOException(t);
            }
        }
        return gz;
    }
}
0 голосов
/ 11 января 2019

Столкнулся с точно такой же проблемой.Я попробовал пример в Javadoc метода BodySubscribers.mapping.Такое же поведение, приложение зависает без ошибок.

Может быть ошибкой, потому что это официальный пример из Javadoc.

  public static <W> BodySubscriber<W> asJSON(Class<W> targetType) {
     BodySubscriber<InputStream> upstream = BodySubscribers.ofInputStream();

     BodySubscriber<W> downstream = BodySubscribers.mapping(
           upstream,
           (InputStream is) -> {
               try (InputStream stream = is) {
                   ObjectMapper objectMapper = new ObjectMapper();
                   return objectMapper.readValue(stream, targetType);
               } catch (IOException e) {
                   throw new UncheckedIOException(e);
               }
           });
    return downstream;
 } }
...