我正在使用新的 java.net.http
处理异步 HTTP 请求+响应交换的类,我正在尝试找到一种方法让 BodySubscriber 处理不同的编码类型,例如 gzip。
然而,映射一个BodySubsriber<InputStream>
以便底层流被 GZIPInputStream
包裹(当在响应 header 中找到“Content-Encoding: gzip”时)导致挂起。没有异常(exception),只是完全停止 Activity 。
映射 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 响应会导致控制台显示如下:
Entered EncodedBodyHandler.apply method.
Entered decodeGzipStream method.
没有看到更多内容,所以调用 GZIPInputStream
之后的行永远不会执行构造函数。
有谁知道为什么要尝试包装 InputStream
来自BodySubscriber<InputStream>
在GZIPInputStream
挂了吗?
注意:未编码(原始文本)HTTP 响应主体的等效方法仅包含对 BodySubscribers.ofInputStream()
的调用没有映射,这允许毫无问题地接收和显示响应。
最佳答案
编辑:JDK-8217264自 JDK13 以来已修复
这确实是一个错误。我已经登录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;
}
}
关于java - 在 GZIPInputStream 中包装 BodySubscriber<InputStream> 导致挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53379087/