Java 包装体订户<;输入流>;在GZIPInputStream中,流导致挂起

Java 包装体订户<;输入流>;在GZIPInputStream中,流导致挂起,java,gzipinputstream,java-http-client,Java,Gzipinputstream,Java Http Client,我正在使用新的java.net.http类来处理异步http请求+响应交换,并试图找到一种方法让BodySubscriber处理不同的编码类型,例如gzip 但是,映射bodysubscriber,使基础流被gzip输入流包装(当在响应头中找到“Content Encoding:gzip”时),会导致挂起。没有例外,只是完全停止活动 映射BodySubscriber的代码如下所示: private HttpResponse.BodySubscriber<InputStream> gz

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

但是,映射
bodysubscriber
,使基础流被
gzip输入流
包装(当在响应头中找到“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);
    }
}
private-HttpResponse.BodySubscriber gzip-BodySubscriber(
HttpResponse.ResponseInfo(响应信息){
返回HttpResponse.BodySubscribers.mapping(
HttpResponse.BodySubscribers.ofInputStream(),
这个::decodeGzipStream);
}
专用InputStream decodeGzipStream(InputStream GzipEdStream){
System.out.println(“输入解码流方法”);
试一试{
InputStream decodedStream=新的GZIPInputStream(gzippedStream);
System.out.println(
“创建了GZIPInputStream来处理响应体流。”);
返回解码流;
}捕获(IOEX异常){
System.out.println(“尝试创建GZIPInputStream时发生IOException。”);
抛出新的未选中异常(ex);
}
}
接收到具有“gzip”编码的HTTP响应将导致控制台显示以下内容:

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

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

有人知道为什么将
BodySubscriber
中的
InputStream
包装到
GZIPInputStream
中的尝试挂起了吗


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

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

这可能是一个bug,因为这是来自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;
 } }
publicstaticbodysubscriber asJSON(类targetType){
BodySubscriber上游=BodySubscribers.ofInputStream();
BodySubscriber下游=BodySubscribers.mapping(
上游
(输入流是)->{
try(InputStream=is){
ObjectMapper ObjectMapper=新的ObjectMapper();
返回objectMapper.readValue(流,targetType);
}捕获(IOE异常){
抛出新的未选中异常(e);
}
});
返回下游;
} }

这确实是一个bug。我已经登录了。我可以建议两种解决方法:

解决方案一 不要使用
BodySubscribers.mapping
——而是在获取HttpResponse的主体后,将
InputStream
转换为
GZIPInputStream

GZIPInputStream gzin = new GZIPInputStream(resp.getBody());
解决方案二 让映射函数返回一个
Supplier
,注意在调用
Supplier::get
之前不要创建
gziInputStream

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;
    }
}
静态最终类ISS实现供应商{
最终输入流输入;
gzip输入流gz;
ISS(输入流输入){
this.in=in;
}
公共同步InputStream get(){
if(gz==null){
试一试{
gz=新的GZIPInputStream(in);
}捕获(IOT异常){
抛出新的未选中异常(t);
}
}
返回gz;
}
}

注意:如果有人知道如何格式化上面的代码片段,我将不胜感激。单击编辑器上的{}按钮似乎不起作用。似乎编号列表内容对代码示例不起作用,因此我将编号列表替换为标题部分。(请随意编辑标题以提供更具描述性的名称。)顺便说一句,最后我使用了
新的gzip输入流(response.getBody())
解决方法,如.Ah。。。谢谢你的信息!下次我会记住的:-)