我正在使用apache async http客户端从azure存储流中传输对象。
我只需要返回具有关联流的HttpResponse对象。我的客户实际上必须从该流中读取以在本地存储该文件。
所以Apache Async客户端使用BasicAsyncResponseConsumer,它实际上在调用完成的回调之前将整个文件缓冲在本地内存中。
我正在尝试创建自己的AbstractAsyncResponseConsumer实现,以便我可以流式传输响应体,而不是实际存储它,但直到现在都没有成功。
以下是裸骨cosumer类供参考 - >
public class MyConsumer extends` AbstractAsyncResponseConsumer<HttpResponse> {
@Override
protected void onResponseReceived(HttpResponse response) throws HttpException, IOException {
}
@Override
protected void onContentReceived(ContentDecoder decoder, IOControl ioctrl) throws IOException {
}
@Override
protected void onEntityEnclosed(HttpEntity entity, ContentType contentType) throws IOException {
}
@Override
protected HttpResponse buildResult(HttpContext context) throws Exception {
return null;
}
@Override
protected void releaseResources() {
}
}
以下是发送请求并返回响应的代码 - &gt;
public void getFile(HttpRequestBase request) {
MyConsumer myConsumer = new MyConsumer();
HttpAsyncRequestProducer producer =
HttpAsyncMethods.create(request);
CompletableFuture<HttpResponse> future = new CompletableFuture<>();
return Future<HttpResponse> responseFuture =
httpclient.execute(producer,myConsumer,
new FutureCallback<HttpResponse>() {
@Override
public void completed(HttpResponse result) {
//This is called only when all the response body has been read
//future.complete(Result)
}
@Override
public void failed(Exception ex) {
}
@Override
public void cancelled() {
}
});
return future;
}
我将向客户返回HttpResponse对象的CompletableFuture。
他们不应该等待我的http客户端首先在本地缓冲区中读取所有响应主体。
理想情况下,它们应该直接从响应对象中提供的流开始复制。
我应该在消费者的实施中添加什么才能获得理想的结果?
答案 0 :(得分:1)
我不知道您是否仍然遇到此问题,但是如果您想要的是实际流传输数据的InputStream
,那么您将要使用Apache HttpClient的阻塞版本。
Java的内置InputStream
和OutputStream
本质上是阻塞的,因此返回CompletableFuture
中的InputStream
根本无法达到目的。 BasicAsyncResponseConsumer
在内存中缓冲整个响应实际上是正确的做法,因为这是使其真正无阻塞的唯一方法。
您可以查看的另一个选项是HttpAsyncMethods.createZeroCopyConsumer
。它的作用是以完全无阻塞的方式将内容存储到文件中。
这是一个示例:
try (CloseableHttpAsyncClient client = HttpAsyncClients.createDefault()) {
client.start();
final CompletableFuture<HttpResponse> cf = new CompletableFuture<>();
client.execute(
HttpAsyncMethods.createGet("https://example.com"),
HttpAsyncMethods.createZeroCopyConsumer(new File("foo.html")),
new FutureCallback<HttpResponse>() {
@Override
public void completed(HttpResponse result) {
cf.complete(result);
}
@Override
public void failed(Exception ex) {
cf.completeExceptionally(ex);
}
@Override
public void cancelled() {
cf.cancel(true);
}
});
// When cf completes, the file will be ready.
// The InputStream inside the HttpResponse will be the FileInputStream of the created file.
}