如何在 HttpResponse.BodyHandler 中使用 InputStream?
How to consume an InputStream in an HttpResponse.BodyHandler?
我正在尝试为 Java 11 HttpClient 构建一个 JSON 处理程序。
我遇到的问题是,尝试与 BodySubscribers.ofInputStream()
组合会导致永远不会从流中读取任何数据,并永远挂起。
@Override
public HttpResponse.BodySubscriber<Void> apply(HttpResponse.ResponseInfo responseInfo) {
return HttpResponse.BodySubscribers.mapping(
HttpResponse.BodySubscribers.ofInputStream(),
inputStream -> {
try {
System.out.print(inputStream.read());
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return null;
}
);
}
相比之下,返回流并在之后读取它是可行的。
InputStream inputStream = client.send(request, HttpResponse.BodyHandlers.ofInputStream()).body();
System.out.print(inputStream.read()); // out: 123
我错过了什么?
这里的问题在于在不应阻塞的线程中调用阻塞操作。实际上 - 有两个问题:
- Java11API 文档提示您可以这样做 - 这确实不是一个好主意。
- 实现未准备好处理映射器函数中的阻塞操作。
JDK-8217264: HttpClient: Blocking operations in mapper function do not work as documented
在 13 中修复了这两个问题
如果您查看 more recent version of the API documentation,您会发现它现已更新以涵盖此案例。
尽管从 13 开始这样做将不再楔入请求,但仍然不鼓励阻塞映射器的函数,因为它会阻塞 HttpClient 的执行线程之一,直到响应被完全接收,这可能导致线程饥饿。
为了补充我的回答 - 您应该考虑遵循较新的 API 文档和 return 的建议 Supplier<JSONObject>
而不是 JSONObject
,这将允许延迟流的读取(和阻塞操作),直到 Supplier::get
被调用者调用。这使您可以灵活地选择哪个线程将阻塞等待响应。
我正在尝试为 Java 11 HttpClient 构建一个 JSON 处理程序。
我遇到的问题是,尝试与 BodySubscribers.ofInputStream()
组合会导致永远不会从流中读取任何数据,并永远挂起。
@Override
public HttpResponse.BodySubscriber<Void> apply(HttpResponse.ResponseInfo responseInfo) {
return HttpResponse.BodySubscribers.mapping(
HttpResponse.BodySubscribers.ofInputStream(),
inputStream -> {
try {
System.out.print(inputStream.read());
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return null;
}
);
}
相比之下,返回流并在之后读取它是可行的。
InputStream inputStream = client.send(request, HttpResponse.BodyHandlers.ofInputStream()).body();
System.out.print(inputStream.read()); // out: 123
我错过了什么?
这里的问题在于在不应阻塞的线程中调用阻塞操作。实际上 - 有两个问题:
- Java11API 文档提示您可以这样做 - 这确实不是一个好主意。
- 实现未准备好处理映射器函数中的阻塞操作。
JDK-8217264: HttpClient: Blocking operations in mapper function do not work as documented
在 13 中修复了这两个问题如果您查看 more recent version of the API documentation,您会发现它现已更新以涵盖此案例。 尽管从 13 开始这样做将不再楔入请求,但仍然不鼓励阻塞映射器的函数,因为它会阻塞 HttpClient 的执行线程之一,直到响应被完全接收,这可能导致线程饥饿。
为了补充我的回答 - 您应该考虑遵循较新的 API 文档和 return 的建议 Supplier<JSONObject>
而不是 JSONObject
,这将允许延迟流的读取(和阻塞操作),直到 Supplier::get
被调用者调用。这使您可以灵活地选择哪个线程将阻塞等待响应。