如何使用java.net.http.HttpClient记录请求/响应?

问题描述 投票:8回答:3

在Java 9中实验性地引入的HttpClient现在在Java 11中是稳定的,但毫不奇怪,很少有项目似乎实际使用它。文档几乎不存在。

在进行HTTP调用时,最常见的一个问题是记录请求/响应。你如何使用HttpClient做到这一点,当然不会在每次通话中手动记录它?是否有像所有其他HTTP客户端提供的拦截器机制?

java logging java-9 java-11 java-http-client
3个回答
6
投票

如果我们查看jdk.internal.net.http.common.DebugLogger源代码,我们可以看到一些使用System.Logger的记录器,而System.LoggerFinder将使用-Djdk.internal.httpclient.debug=true来选择记录器框架。 JUL是默认选择。记录器名称是:

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

可以通过将它们设置为系统属性来启用它们。例如,使用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) ... 运行将产生:

-Djdk.httpclient.HttpClient.log=requests

8
投票

您可以通过在Java命令行上指定http://hg.openjdk.java.net/jdk/jdk/file/tip/test/jdk/java/net/httpclient/offline/来记录请求和响应。

至于测试/模拟,你可能想看看离线测试:http://openjdk.java.net/groups/net/httpclient/index.html

根据您要实现的目标,您可以使用“DelegatingHttpClient”来拦截和记录请求和响应。

除了Java API文档之外,还有一些jdk.httpclient.HttpClient.log的高级文档

附加说明:

-Djdk.httpclient.HttpClient.log= errors,requests,headers, frames[:control:data:window:all],content,ssl,trace,channel 属性是一个特定于实现的属性,其值为逗号分隔列表,可以在Java命令行上进行配置以进行诊断/调试,并使用以下值:

-Djdk.internal.httpclient.debug

0
投票

在我们这边,我们没有发现send提供的日志记录足够可读。我们提出的解决方案是使用装饰器包装HttpClient,该装饰器将能够拦截调用并提供日志记录。在这里它是如何看起来(不仅应该为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() { } }

qazxswpoi
© www.soinside.com 2019 - 2024. All rights reserved.