我正在使用新的java.net.http
类来处理异步HTTP请求和响应交换,并且我试图找到一种方法使BodySubscriber处理不同的编码类型,例如gzip。
但是,映射BodySubsriber<InputStream>
以便基础流被GZIPInputStream
包装(当在响应标头中找到“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响应,控制台将显示以下内容:
输入了EncodedBodyHandler.apply方法。
输入了encodeGzipStream方法。
什么也看不到,因此永远不会执行对
GZIPInputStream
构造函数的调用之后的行。有谁知道为什么这种尝试将
InputStream
中的BodySubscriber<InputStream>
包装在GZIPInputStream
中的尝试挂起了?注意:未编码(原始文本)HTTP响应正文的等效方法仅包含对
BodySubscribers.ofInputStream()
的调用,而没有映射,这使得可以毫无问题地接收和显示响应。 最佳答案
这确实是一个错误。我已经记录了JDK-8217264。我可以建议两个解决方法:
解决方法一
不要使用BodySubscribers.mapping
-在获取HttpResponse的主体之后,将InputStream
转换为GZIPInputStream
:
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;
}
}