HttpClient introduit expérimentalement dans Java 9 est maintenant stable dans Java 11, mais sans surprise, très peu de projets semblent réellement utiliser La documentation est presque inexistante.
L'une des demandes les plus courantes lors d'un appel HTTP est l'enregistrement de la demande/réponse. Comment feriez-vous cela en utilisant le HttpClient
, sans bien sûr le journaliser manuellement à chaque appel? Existe-t-il un mécanisme d'intercepteur comme celui proposé par tous les autres clients HTTP?
Si nous regardons jdk.internal.net.http.common.DebugLogger
code source, nous pouvons voir quelques enregistreurs utilisant System.Logger
, qui à son tour utilisera System.LoggerFinder
pour sélectionner la structure de l'enregistreur. JUL est le choix par défaut. Les noms des enregistreurs sont:
Ils peuvent être activés en les définissant comme propriété système. Par exemple, exécuter avec -Djdk.internal.httpclient.debug=true
produira:
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)
...
Vous pouvez consigner les demandes et les réponses en spécifiant -Djdk.httpclient.HttpClient.log=requests
sur la ligne de commande Java.
En ce qui concerne les tests/moqueries, vous voudrez peut-être jeter un œil au test hors ligne: http://hg.openjdk.Java.net/jdk/jdk/file/tip/test/jdk/Java/net/httpclient/hors ligne /
Selon ce que vous cherchez à réaliser, vous pouvez également utiliser un "DelegatingHttpClient" pour intercepter et enregistrer les demandes et les réponses.
Outre la Java, il existe également une documentation de haut niveau sur http://openjdk.Java.net/groups/net/httpclient/index.html
Remarque additionnelle:
Le jdk.httpclient.HttpClient.log
La propriété est une propriété spécifique à l'implémentation dont la valeur est une liste séparée par des virgules qui peut être configurée sur la ligne de commande Java à des fins de diagnostic/débogage avec les valeurs suivantes:
-Djdk.httpclient.HttpClient.log=
errors,requests,headers,
frames[:control:data:window:all],content,ssl,trace,channel
De notre côté, nous n'avons pas trouvé la journalisation fournie par -Djdk.internal.httpclient.debug
assez lisible. La solution que nous avons trouvée consiste à envelopper le HttpClient avec un décorateur qui pourra intercepter les appels et fournir la journalisation. Voici à quoi cela ressemble (devrait être fait non seulement pour les méthodes send
mais 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);
}
}
Et voici le 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() {
}
}