在 GZIPInputStream 中包装 BodySubscriber<InputStream> 会导致挂起

Bob*_*ous 5 java gzipinputstream java-http-client

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

但是,映射 aBodySubsriber<InputStream>以使底层流被 a 包装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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

没有看到更多内容,因此调用GZIPInputStream构造函数之后的行永远不会执行。

有谁知道为什么这种将 aInputStream包裹BodySubscriber<InputStream>在 a 中的尝试GZIPInputStream被挂​​起?

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

dan*_*iel 5

编辑JDK-8217264自 JDK13 以来已修复


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

解决方法一

不要使用- ,而是在获取 HttpResponse 的主体后将BodySubscribers.mapping其转换InputStream为 a :GZIPInputStream

GZIPInputStream gzin = new GZIPInputStream(resp.getBody());
Run Code Online (Sandbox Code Playgroud)

解决方法二

让映射函数返回a Supplier<InputStream>,注意不要创建GZIPInputStreamuntilSupplier::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;
    }
}
Run Code Online (Sandbox Code Playgroud)