【问题标题】:Wrapping BodySubscriber<InputStream> in GZIPInputStream leads to hang在 GZIPInputStream 中包装 BodySubscriber<InputStream> 导致挂起
【发布时间】:2018-11-19 16:39:04
【问题描述】:

我正在使用新的 java.net.http 类来处理异步 HTTP 请求+响应交换,并且我正在尝试找到一种方法让 BodySubscriber 处理不同的编码类型,例如 gzip。

但是,映射BodySubsriber&lt;InputStream&gt; 以便底层流被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);
    }
}

接收具有“gzip”编码的 HTTP 响应会导致控制台显示以下内容:

进入 EncodedBodyHandler.apply 方法。
进入decodeGzipStream方法。

什么都没有看到,所以调用 GZIPInputStream 构造函数之后的行永远不会执行。

有谁知道为什么将BodySubscriber&lt;InputStream&gt; 中的InputStream 包装在GZIPInputStream 中的尝试失败了?

注意:未编码(原始文本)HTTP 响应正文的等效方法仅包含对 BodySubscribers.ofInputStream() 的调用,没有映射,这样可以毫无问题地接收和显示响应。

【问题讨论】:

    标签: java gzipinputstream java-http-client


    【解决方案1】:

    这确实是一个错误。我已经登录JDK-8217264。我可以建议两种解决方法:

    解决方法一

    不要使用BodySubscribers.mapping - 而是在获取 HttpResponse 的正文后将 InputStream 转换为 GZIPInputStream

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

    解决方法二

    让映射函数返回 Supplier&lt;InputStream&gt;,注意在调用 Supplier::get 之前不要创建 GZIPInputStream

    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;
        }
    }
    

    【讨论】:

    • 注意:如果有人知道如何格式化上面的代码 sn-p,我将不胜感激。点击编辑器上的 {} 按钮似乎不起作用。
    • 似乎编号列表内容与代码示例不兼容,因此我已将您的编号列表替换为标题部分。 (请随意编辑标题,为它们提供更具描述性的名称。)顺便说一句,最后我采用了new GZIPInputStream(response.getBody()) 解决方法,如my answer to another question 所示。
    • 啊...感谢您的信息!下次我会记住的:-)
    【解决方案2】:

    遇到了完全相同的问题。我尝试了BodySubscribers.mapping 方法的Javadoc 中的示例。同样的行为,应用程序挂起没有任何错误。

    可能是一个错误,因为这是来自 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;
     } }
    

    【讨论】:

      猜你喜欢
      • 2013-12-20
      • 2013-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-11
      • 2014-08-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多