Как зарегистрировать запрос / ответ, используя java.net.http.HttpClient? - PullRequest
0 голосов
/ 08 ноября 2018

HttpClient , введенный экспериментально в Java 9, теперь стабилен в Java 11, но неудивительно, что очень немногие проекты действительно его используют. Документация практически не существует.

Одной из самых распространенных просьб при совершении HTTP-вызова является регистрация запроса / ответа. Как бы вы сделали это, используя HttpClient, без необходимости регистрировать его вручную при каждом вызове? Существует ли механизм перехватчика, подобный тому, который предлагается всеми другими клиентами HTTP?

Ответы [ 3 ]

0 голосов
/ 09 ноября 2018

Вы можете регистрировать запросы и ответы, указав -Djdk.httpclient.HttpClient.log=requests в командной строке Java.

Что касается тестирования / насмешек, вы можете взглянуть на автономный тест: http://hg.openjdk.java.net/jdk/jdk/file/tip/test/jdk/java/net/httpclient/offline/

В зависимости от того, чего вы хотите достичь, вы можете использовать «DelegatingHttpClient» для перехвата и регистрации запросов и ответов.

Помимо документации по Java API, есть также документация высокого уровня на http://openjdk.java.net/groups/net/httpclient/index.html

Дополнительные примечания:

Свойство jdk.httpclient.HttpClient.log является специфичным для реализации свойством, значение которого представляет собой список через запятую, который можно настроить в командной строке Java для диагностики / отладки со следующими значениями:

-Djdk.httpclient.HttpClient.log=
       errors,requests,headers,
       frames[:control:data:window:all],content,ssl,trace,channel
0 голосов
/ 01 апреля 2019

С нашей стороны, мы не нашли протоколирование, предоставляемое -Djdk.internal.httpclient.debug достаточно читабельным. Решение, которое мы придумали, заключается в том, чтобы обернуть HttpClient декоратором, который сможет перехватывать вызовы и обеспечивать ведение журнала. Вот как это выглядит (должно быть сделано не только для send, но и sendAsync методов):

public class HttpClientLoggingDecorator extends HttpClient {

  private static final Logger logger = Logger.getLogger(HttpClientLoggingDecorator.class.getName());

  private final HttpClient client;

  ...

  @Override
  public <T> HttpResponse<T> send(HttpRequest req, HttpResponse.BodyHandler<T> responseBodyHandler)
    throws IOException,
      InterruptedException
  {
    subscribeLoggerToRequest(req);

    HttpResponse<T> response = client.send(req, responseBodyHandler);

    logResponse(response);
    return response;
  }

  private void subscribeLoggerToRequest(HttpRequest req) {
    // define a consumer for how you want to log
    // Consumer<String> bodyConsumer = ...;
    if (req.bodyPublisher().isPresent()) {
      req.bodyPublisher()
              .ifPresent(bodyPublisher -> bodyPublisher.subscribe(new HttpBodySubscriber(bodyConsumer)));
    } else {
      bodyConsumer.accept(NO_REQUEST_BODY);
    }
  }

  private <T> void logResponse(HttpResponse<T> response) {
    // String responseLog = ...;
    logger.info(responseLog);
  }

}

А вот и HttpBodySubscriber:

public class HttpBodySubscriber implements Flow.Subscriber<ByteBuffer> {

  private static final long UNBOUNDED = Long.MAX_VALUE;

  private final Consumer<String> logger;

  public HttpBodySubscriber(Consumer<String> logger) {
    this.logger = logger;
  }

  @Override
  public void onSubscribe(Flow.Subscription subscription) {
    subscription.request(UNBOUNDED);
  }

  @Override
  public void onNext(ByteBuffer item) {
    logger.accept(new String(item.array(), StandardCharsets.UTF_8));
  }

  @Override
  public void onError(Throwable throwable) {
  }

  @Override
  public void onComplete() {
  }

}
0 голосов
/ 08 ноября 2018

Если мы посмотрим на исходный код jdk.internal.net.http.common.DebugLogger, мы увидим несколько регистраторов, использующих System.Logger, которые, в свою очередь, будут использовать System.LoggerFinder для выбора структуры регистратора. JUL - выбор по умолчанию. Названия регистратора:

  • jdk.internal.httpclient.debug
  • jdk.internal.httpclient.websocket.debug
  • jdk.internal.httpclient.hpack.debug

Их можно включить, установив их как системное свойство. Например, выполнение с -Djdk.internal.httpclient.debug=true даст:

DEBUG: [main] [147ms] HttpClientImpl(1) proxySelector is sun.net.spi.DefaultProxySelector@6dde5c8c (user-supplied=false)
DEBUG: [main] [183ms] HttpClientImpl(1) ClientImpl (async) send https://http2.github.io/ GET
DEBUG: [main] [189ms] Exchange establishing exchange for https://http2.github.io/ GET,
     proxy=null
DEBUG: [main] [227ms] PlainHttpConnection(?) Initial receive buffer size is: 43690
DEBUG: [main] [237ms] PlainHttpConnection(SocketTube(1)) registering connect event
DEBUG: [HttpClient-1-SelectorManager] [239ms] SelectorAttachment Registering jdk.internal.net.http.PlainHttpConnection$ConnectEvent@354bf356 for 8 (true)
...
...