1

我正在使用 apache async http 客户端从 azure 存储中流式传输对象。

我只需要返回关联流的 HttpResponse 对象。我的客户实际上必须从该流中读取以在本地存储文件。

因此,Apache Async 客户端使用 BasicAsyncResponseConsumer 在调用完成的回调之前实际上将整个文件缓冲在本地内存中。

我正在尝试创建自己的 AbstractAsyncResponseConsumer 实现,以便我可以流式传输响应主体,而不是首先实际存储它,但到目前为止还没有成功。

这是供参考的基本消费者类->

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() {

}

}

这是发送请求并返回响应的代码->

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 客户端首先在本地缓冲区中读取所有响应正文。

理想情况下,他们应该直接从响应对象中提供的流开始复制。

我应该在消费者的实现中添加什么以获得所需的结果?

4

1 回答 1

1

我不知道你是否还有这个问题,但如果你想要的是InputStream真正流式传输数据,那么你会想要使用 Apache HttpClient 的阻塞版本。

Java 是内置的InputStream并且OutputStream本质上是阻塞的,因此返回 a CompletableFutureofInputStream基本上违背了目的。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.
        }
于 2019-01-09T18:53:22.163 回答