Is it possible to intercept request body send via the apache httpcomponents client5?

50 Views Asked by At

I am using OpenSearchClient which uses the apache https client5 internally to communicate with the opensearch server. I need to intercept the search request that is sent from the application to the opensearch server (i.e. to log the search query). For this, I tried to add a HttpRequestInterceptor that will intercept the request and log the entity. But, the body retrieval from the EntityDetails is not possible in this case. Following code is the config I am using:-

  public OpenSearchClient opensearchClient() {
    val builder = ApacheHttpClient5TransportBuilder.builder(new HttpHost(protocol, host, port));
    builder.setHttpClientConfigCallback(
        httpClientBuilder -> {
          val connectionManager =
              PoolingAsyncClientConnectionManagerBuilder.create()
                  .setDefaultConnectionConfig(
                      ConnectionConfig.custom()
                          .setConnectTimeout(timeout, TimeUnit.MILLISECONDS)
                          .setSocketTimeout(3000, TimeUnit.MILLISECONDS)
                          .build())
                  .build();

          return httpClientBuilder
              .setConnectionManager(connectionManager)
              .addRequestInterceptorFirst(
                  (request, entity, context) -> {
                    log.info("Class: {}", entity.getClass());
                    log.info("Package: {}", entity.getClass().getPackageName());
                    log.info("Name: {}", entity.getClass().getName());

                  });
        });

    return new OpenSearchClient(builder.build());
}

The EntityDetails here is an instance of InternalAbstractHttpAsyncClient that I could see using the debugger. Seems like extraction of the request body from it is not straightforward. The logs are below:

2024-03-20T12:26:04.998+06:00  INFO 382364 --- [ient-dispatch-1] n.n.i.s.api.config.OpenSearchConfig      : Class: class org.apache.hc.client5.http.impl.async.InternalAbstractHttpAsyncClient$2
2024-03-20T12:26:04.999+06:00  INFO 382364 --- [ient-dispatch-1] n.n.i.s.api.config.OpenSearchConfig      : Package: org.apache.hc.client5.http.impl.async
2024-03-20T12:26:05.000+06:00  INFO 382364 --- [ient-dispatch-1] n.n.i.s.api.config.OpenSearchConfig      : Name: org.apache.hc.client5.http.impl.async.InternalAbstractHttpAsyncClient$2

My goal is to retrieve the request body from the entity. The apache http client5 docs suggest to use decorator pattern to achieve such behavior. Any help would be appreciated.

1

There are 1 best solutions below

0
ok2c On

Yes, of course, it is, but one needs to use a request execution interceptor for that end.

In the example below a custom execution interceptor buffers content of the request entity if its not repeatable in order to make it repeatable, so that the request could be automatically redirected or re-authenticated

try (final CloseableHttpClient httpclient = HttpClients.custom()
        .addExecInterceptorFirst("custom", (request, scope, chain) -> {
            HttpEntity entity = request.getEntity();
            if (entity != null && !entity.isRepeatable()) {
                request.setEntity(new BufferedHttpEntity(entity));
            }
            return chain.proceed(request, scope);
        })
        .build()) {

    final HttpGet httpget = new HttpGet("http://httpbin.org/get");
    System.out.println("Executing request " + httpget.getMethod() + " " + httpget.getUri());
    httpclient.execute(httpget, response -> {
        System.out.println("----------------------------------------");
        System.out.println(httpget + "->" + new StatusLine(response));
        EntityUtils.consume(response.getEntity());
        return null;
    });
}