如何使用HttpAsyncClient创建流水线中继请求?

时间:2015-01-15 22:04:26

标签: java apache-httpclient-4.x asynchttpclient

我使用Apache的HttpAsyncClient代理或中继传入的请求到另一台服务器。我有简单的案例工作(下面的示例代码)。

问题在于Future<HttpResponse>会将响应保留在内存中,等待它完成之前完成阅读。我们有一些呼叫具有非常大的响应体,所以我想做的是一个&#34;管道&#34;或&#34;零拷贝&#34;策略,我只是传递身体内容,而不是将整个反应保存在记忆中。

Apache Http Client提供ZeroCopyPostZeroCopyConsumer,但它们在Files而不是流(即响应的OutputStream)上运行。

如何编写代码以将远程响应中的字节直接传递回原始响应?

到目前为止我的代码:

    try {
        httpClient.start();

        Future<HttpResponse> future = httpClient.execute(method, null);
        HttpResponse remoteResponse = future.get();

        relayStatus(remoteResponse, originalResponse);
        relayHeaders(remoteResponse, originalResponse);
        relayBody(remoteResponse, originalResponse);
    }

    catch (IOException | InterruptedException |ExecutionException  e) {
        ...
    }

我一直无法找到执行此操作的直接示例代码,但是在评论中链接的示例会让我走得更远。我认为答案将是使用AsyncByteConsumer

我是否在正确的轨道上?如何扩展它以使用零拷贝策略将中继响应中的正文字节传递回原始响应?

1 个答案:

答案 0 :(得分:0)

所以vanOekel的评论给了我需要的暗示;基于他链接的例子,我创建了一个&#34; PipelineStreamConsumer&#34;然后在httpClient.execute(...)电话中使用它。

我发布此内容给后人,以防万一有人想用更好的答案得分。

Future<HttpResponse> future = httpClient.execute(producer, new PipelineStreamConsumer(originalResponse), null);

...

public class PipelineStreamConsumer extends AsyncByteConsumer<HttpResponse> {

    private final HttpServletResponse response;
    private HttpResponse remoteResponse;

    public PipelineStreamConsumer(HttpServletResponse response) {
        this.response = response;
    }

    @Override
    protected void onResponseReceived(HttpResponse remoteResponse) throws HttpException,
    IOException {
        this.remoteResponse = remoteResponse;
        relayStatus(remoteResponse);
        relayHeaders(remoteResponse);
    }

    @Override
    protected HttpResponse buildResult(HttpContext context) throws Exception {
        return remoteResponse;
    }

    @Override
    protected void onByteReceived(ByteBuffer buffer, IOControl control)
            throws IOException {
        WritableByteChannel channel = Channels.newChannel(outputStream);
        channel.write(buffer);
    }
}