在 GZIPInputStream 中包装 BodySubscriber<InputStream> 导致挂起
Wrapping BodySubscriber<InputStream> in GZIPInputStream leads to hang
我正在使用新的 java.net.http
类 来处理异步 HTTP 请求+响应交换,并且我正在尝试找到一种方法让 BodySubscriber 处理不同的编码类型,例如 gzip .
但是,映射 BodySubsriber<InputStream>
以便底层流被 GZIPInputStream
包装(当在响应 header 中找到 "Content-Encoding: gzip" 时)会导致挂起.没有例外,只是 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
构造函数之后的行。
有谁知道为什么这种将 BodySubscriber<InputStream>
中的 InputStream
包裹在 GZIPInputStream
中的尝试会挂起?
注意:未编码(原始文本)HTTP 响应主体的等效方法只包含对 BodySubscribers.ofInputStream()
的调用,没有映射,这允许毫无问题地接收和显示响应。
遇到了完全相同的问题。我尝试了 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;
} }
这确实是一个错误。我已经登录 JDK-8217264。我可以建议两种解决方法:
解决方法一
不要使用 BodySubscribers.mapping
- 但在获取 HttpResponse 的正文后将 InputStream
转换为 GZIPInputStream
:
GZIPInputStream gzin = new GZIPInputStream(resp.getBody());
解决方法二
将映射函数 return 改为 Supplier<InputStream>
,注意在调用 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;
}
}
我正在使用新的 java.net.http
类 来处理异步 HTTP 请求+响应交换,并且我正在尝试找到一种方法让 BodySubscriber 处理不同的编码类型,例如 gzip .
但是,映射 BodySubsriber<InputStream>
以便底层流被 GZIPInputStream
包装(当在响应 header 中找到 "Content-Encoding: gzip" 时)会导致挂起.没有例外,只是 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
构造函数之后的行。
有谁知道为什么这种将 BodySubscriber<InputStream>
中的 InputStream
包裹在 GZIPInputStream
中的尝试会挂起?
注意:未编码(原始文本)HTTP 响应主体的等效方法只包含对 BodySubscribers.ofInputStream()
的调用,没有映射,这允许毫无问题地接收和显示响应。
遇到了完全相同的问题。我尝试了 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;
} }
这确实是一个错误。我已经登录 JDK-8217264。我可以建议两种解决方法:
解决方法一
不要使用 BodySubscribers.mapping
- 但在获取 HttpResponse 的正文后将 InputStream
转换为 GZIPInputStream
:
GZIPInputStream gzin = new GZIPInputStream(resp.getBody());
解决方法二
将映射函数 return 改为 Supplier<InputStream>
,注意在调用 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;
}
}