Exploration du nouveau client HTTP en Java 9

Exploration du nouveau client HTTP dans Java 9 et 11

1. introduction

Dans ce didacticiel, nous allons explorer les nouveauxhttps://docs.oracle.com/javase/9/docs/api/jdk/incubator/http/HttpClient.html. d'incubation de Java 9

Jusqu'à très récemment, Java ne fournissait que l'APIHttpURLConnection - qui est de bas niveau et n'est pas connue pour être la convivialité de and riche en fonctionnalités.

Par conséquent, certaines bibliothèques tierces largement utilisées étaient couramment utilisées, telles queApache HttpClient,Jetty et Spring'sRestTemplate.

2. La configuration initiale

The HTTP Client module is bundled as an incubator module dans JDK 9 et prend en charge lesHTTP/2 avec une compatibilité descendante facilitant toujours HTTP / 1.1.

Pour l'utiliser, nous devons définir notre module à l'aide d'un fichiermodule-info.java qui indique également le module requis pour exécuter notre application:

module com.example.java9.httpclient {
  requires jdk.incubator.httpclient;
}

3. Présentation de l'API du client HTTP

Contrairement àHttpURLConnection, HTTP Client fournit des mécanismes de requête synchrones et asynchrones.

L'API comprend 3 classes principales:

  • HttpRequest représente la requête à envoyer via lesHttpClient

  • HttpClient se comporte comme un conteneur pour les informations de configuration communes à plusieurs requêtes

  • HttpResponse représente le résultat d'un appelHttpRequest

Nous examinerons chacun d’entre eux plus en détail dans les sections suivantes. Tout d'abord, concentrons-nous sur une demande.

4. HttpRequest

HttpRequest, comme nomsuggests, est un objet qui représente la demande que nous voulons envoyer. De nouvelles instances peuvent être créées à l'aide deHttpRequest.Builder.

Nous pouvons l'obtenir en appelantHttpRequest.newBuilder(). La classeBuilder fournit un tas de méthodes que nous pouvons utiliser pour configurer notre requête.

Nous couvrirons les plus importants.

4.1. Réglage deURI

La première chose à faire lors de la création d'une demande est de fournir l'URL.

Nous pouvons le faire de deux manières - en utilisant le constructeur pourBuilder avec le paramètreURI ou en appelant la méthodeuri(URI) sur l'instanceBuilder:

HttpRequest.newBuilder(new URI("https://postman-echo.com/get"))

HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))

La dernière chose à configurer pour créer une requête de base est une méthode HTTP.

4.2. Spécification de la méthode HTTP

Nous pouvons définir la méthode HTTP que notre requête utilisera en appelant l'une des méthodes deBuilder:

  • AVOIR()

  • POST (corps BodyProcessor)

  • PUT (corps BodyProcessor)

  • DELETE (corps BodyProcessor)

Nous aborderonsBodyProcessor en détail plus tard. Maintenant, créons simplementa very simple GET request example:

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))
  .GET()
  .build();

Cette requête a tous les paramètres requis parHttpClient. Cependant, nous devons parfois ajouter des paramètres supplémentaires à notre demande. En voici quelques-unes importantes:

  • la version du protocole HTTP

  • en-têtes

  • un délai d'attente

4.3. Définition de la version du protocole HTTP

L'API exploite pleinement le protocole HTTP / 2 et l'utilise par défaut, mais nous pouvons définir la version du protocole à utiliser.

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))
  .version(HttpClient.Version.HTTP_2)
  .GET()
  .build();

Il est important de mentionner ici que le client utilisera, par exemple, HTTP / 1.1 si HTTP / 2 n'est pas pris en charge.

4.4. Définition des en-têtes

Si nous voulons ajouter des en-têtes supplémentaires à notre demande, nous pouvons utiliser les méthodes de générateur fournies.

Nous pouvons le faire de deux manières:

  • passer tous les en-têtes sous forme de paires clé-valeur à la méthodeheaders() ou par

  • en utilisant la méthodeheader() pour l'en-tête de valeur-clé unique:

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))
  .headers("key1", "value1", "key2", "value2")
  .GET()
  .build();

HttpRequest request2 = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))
  .header("key1", "value1")
  .header("key2", "value2")
  .GET()
  .build();

La dernière méthode utile que nous pouvons utiliser pour personnaliser notre requête esta timeout().

4.5. Définition d'un délai

Définissons maintenant la durée pendant laquelle nous voulons attendre une réponse.

Si le temps défini expire, unHttpTimeoutException sera lancé; le délai d'expiration par défaut est défini sur l'infini.

Le délai d'expiration peut être défini avec l'objetDuration - en appelant la méthodetimeout() sur l'instance du générateur:

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))
  .timeout(Duration.of(10, SECONDS))
  .GET()
  .build();

5. Définition d'un corps de requête

Nous pouvons ajouter un corps à une requête en utilisant les méthodes du générateur de requêtes:POST(BodyProcessor body),PUT(BodyProcessor body) etDELETE(BodyProcessor body).

La nouvelle API fournit un certain nombre d'implémentations deBodyProcessor prêtes à l'emploi qui simplifient le passage du corps de la requête:

  • StringProcessor (lit le corps d'unString, créé avecHttpRequest.BodyProcessor.fromString)

  • InputStreamProcessor (lit le corps d'unInputStream, créé avecHttpRequest.BodyProcessor.fromInputStream)

  • ByteArrayProcessor (lit le corps d'un tableau d'octets, créé avecHttpRequest.BodyProcessor.fromByteArray)

  • FileProcessor (lit le corps d'un fichier au chemin donné, créé avecHttpRequest.BodyProcessor.fromFile)

Dans le cas où nous n’avons pas besoin d’un corps, nous pouvons simplement passer unHttpRequest.noBody():

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/post"))
  .POST(HttpRequest.noBody())
  .build();

5.1. StringBodyProcessor

La définition d'un corps de requête avec une implémentation deBodyProcessor est très simple et intuitive.

Par exemple, si nous voulons passer un simpleString comme corps, nous pouvons utiliserStringBodyProcessor.

Comme nous l'avons déjà mentionné, cet objet peut être créé avec une méthode d'usinefromString(); il prend juste un objetString comme argument et crée un corps à partir de celui-ci:

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/post"))
  .headers("Content-Type", "text/plain;charset=UTF-8")
  .POST(HttpRequest.BodyProcessor.fromString("Sample request body"))
  .build();

5.2. InputStreamBodyProcessor

Pour ce faire, leInputStream doit être passé en tant queSupplier (pour rendre sa création paresseuse), donc c'est un peu différent de celui décrit ci-dessusStringBodyProcessor.

Cependant, ceci est également assez simple:

byte[] sampleData = "Sample request body".getBytes();
HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/post"))
  .headers("Content-Type", "text/plain;charset=UTF-8")
  .POST(HttpRequest.BodyProcessor
   .fromInputStream(() -> new ByteArrayInputStream(sampleData)))
  .build();

Remarquez comment nous avons utilisé un simpleByteArrayInputStream ici; cela peut bien sûr être n'importe quelle implémentation deInputStream.

5.3. ByteArrayProcessor

Nous pouvons également utiliserByteArrayProcessor et passer un tableau d'octets comme paramètre:

byte[] sampleData = "Sample request body".getBytes();
HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/post"))
  .headers("Content-Type", "text/plain;charset=UTF-8")
  .POST(HttpRequest.BodyProcessor.fromByteArray(sampleData))
  .build();

5.4. FileProcessor

Pour travailler avec un fichier, nous pouvons utiliser lesFileProcessor fournis; sa méthode de fabrique prend un chemin vers le fichier en tant que paramètre et crée un corps à partir du contenu:

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/post"))
  .headers("Content-Type", "text/plain;charset=UTF-8")
  .POST(HttpRequest.BodyProcessor.fromFile(
    Paths.get("src/test/resources/sample.txt")))
  .build();

Nous avons expliqué comment créer desHttpRequest et comment y définir des paramètres supplémentaires.

Il est maintenant temps d’examiner de plus près la classeHttpClient qui est responsable de l’envoi des requêtes et de la réception des réponses.

6. HttpClient

Toutes les demandes sont envoyées en utilisantHttpClient qui peut être instancié en utilisant la méthodeHttpClient.newBuilder() ou en appelantHttpClient.newHttpClient().

Il fournit de nombreuses méthodes utiles et auto-descriptives que nous pouvons utiliser pour gérer notre demande / réponse.

Couvrons-en quelques-uns ici.

6.1. Définition d'un proxy

Nous pouvons définir un proxy pour la connexion. Appelez simplement la méthodeproxy() sur une instanceBuilder:

HttpResponse response = HttpClient
  .newBuilder()
  .proxy(ProxySelector.getDefault())
  .build()
  .send(request, HttpResponse.BodyHandler.asString());

Dans notre exemple, nous avons utilisé le proxy système par défaut.

6.2. Définition de la stratégie de redirection

Parfois, la page à laquelle nous voulons accéder a été déplacée vers une adresse différente.

Dans ce cas, nous recevrons le code d'état HTTP 3xx, généralement avec les informations sur le nouvel URI. HttpClient can redirect the request to the new URI automatically if we set the appropriate redirect policy.

On peut le faire avec la méthodefollowRedirects() surBuilder:

HttpResponse response = HttpClient.newBuilder()
  .followRedirects(HttpClient.Redirect.ALWAYS)
  .build()
  .send(request, HttpResponse.BodyHandler.asString());

Toutes les politiques sont définies et décrites dans enumHttpClient.Redirect.

6.3. Définition deAuthenticator pour une connexion

UnAuthenticator est un objet qui négocie les informations d'identification (authentification HTTP) pour une connexion.

Il fournit différents schémas d’authentification (tels que, par exemple, l’authentification de base ou l’authentification Digest). Dans la plupart des cas, l'authentification nécessite un nom d'utilisateur et un mot de passe pour se connecter à un serveur.

Nous pouvons utiliser la classePasswordAuthentication qui est juste un détenteur de ces valeurs:

HttpResponse response = HttpClient.newBuilder()
  .authenticator(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
      return new PasswordAuthentication(
        "username",
        "password".toCharArray());
    }
}).build()
  .send(request, HttpResponse.BodyHandler.asString());

Dans l'exemple ci-dessus, nous avons passé les valeurs de nom d'utilisateur et de mot de passe en texte clair; bien sûr, dans un scénario de production, cela devra être différent.

Notez que toutes les demandes ne doivent pas utiliser les mêmes nom d'utilisateur et mot de passe. La classeAuthenticator fournit un certain nombre de méthodesgetXXX (par exemple,getRequestingSite()) qui peuvent être utilisées pour savoir quelles valeurs doivent être fournies.

Nous allons maintenant explorer l'une des fonctionnalités les plus utiles des nouveauxHttpClient - les appels asynchrones vers le serveur.

6.4. Envoi de demandes - Synchronisation vs. Async

Nouveau HttpClient offre deux possibilités pour envoyer une demande à un serveur:

  • send(…) – synchronously (se bloque jusqu'à ce que la réponse arrive)

  • sendAsync(…) – asynchronously (n'attend pas la réponse, non bloquant)

Jusqu'à présent, la méthodesend(. ..) attend naturellement une réponse:

HttpResponse response = HttpClient.newBuilder()
  .build()
  .send(request, HttpResponse.BodyHandler.asString());

Cet appel renvoie un objetHttpResponse, et nous sommes sûrs que la prochaine instruction de notre flux d'application ne sera exécutée que lorsque la réponse est déjà là.

Cependant, cela présente de nombreux inconvénients, en particulier lorsque nous traitons de grandes quantités de données.

Donc, maintenant, nous pouvons utiliser la méthodesendAsync(. ..) - qui renvoieCompletableFeature<HttpResponse> -to process a request asynchronously:

CompletableFuture> response = HttpClient.newBuilder()
  .build()
  .sendAsync(request, HttpResponse.BodyHandler.asString());

La nouvelle API peut également traiter plusieurs réponses et diffuser les corps de la demande et de la réponse:

List targets = Arrays.asList(
  new URI("https://postman-echo.com/get?foo1=bar1"),
  new URI("https://postman-echo.com/get?foo2=bar2"));
HttpClient client = HttpClient.newHttpClient();
List> futures = targets.stream()
  .map(target -> client
    .sendAsync(
      HttpRequest.newBuilder(target).GET().build(),
      HttpResponse.BodyHandler.asString())
    .thenApply(response -> response.body()))
  .collect(Collectors.toList());

6.5. Définition deExecutor pour les appels asynchrones

Nous pouvons également définir unExecutor qui fournit des threads à utiliser par des appels asynchrones.

Ainsi, nous pouvons, par exemple, limiter le nombre de threads utilisés pour le traitement des demandes:

ExecutorService executorService = Executors.newFixedThreadPool(2);

CompletableFuture> response1 = HttpClient.newBuilder()
  .executor(executorService)
  .build()
  .sendAsync(request, HttpResponse.BodyHandler.asString());

CompletableFuture> response2 = HttpClient.newBuilder()
  .executor(executorService)
  .build()
  .sendAsync(request, HttpResponse.BodyHandler.asString());

Par défaut, leHttpClient utilise l'exécuteurjava.util.concurrent.Executors.newCachedThreadPool().

6.6. Définition d'unCookieManager

Avec la nouvelle API et le nouveau générateur, il est simple de définir unCookieManager pour notre connexion. Nous pouvons utiliser la méthode du constructeurcookieManager(CookieManager cookieManager) pour définir desCookieManager spécifiques au client.

Par exemple, définissonsCookieManager qui ne permet pas du tout d'accepter les cookies:

HttpClient.newBuilder()
  .cookieManager(new CookieManager(null, CookiePolicy.ACCEPT_NONE))
  .build();

Dans le cas où notreCookieManager autorise le stockage des cookies, nous pouvons y accéder en vérifiantCookieManager depuis nosHttpClient:

httpClient.cookieManager().get().getCookieStore()

Maintenant, concentrons-nous sur la dernière classe de l'API Http - lesHttpResponse.

7. ObjetHttpResponse

La classeHttpResponse représente la réponse du serveur. Il fournit un certain nombre de méthodes utiles, mais les deux plus importantes sont:

  • statusCode() - renvoie le code d'état (typeint) pour une réponse (la classeHttpURLConnection contient des valeurs possibles)

  • body() - renvoie un corps pour une réponse (le type de retour dépend du paramètre de réponseBodyHandler passé à la méthodesend())

L'objet de réponse a une autre méthode utile que nous aborderons commeuri(),headers(),trailers() etversion().

7.1. URI de l'objet de réponse

La méthodeuri() sur l'objet de réponse renvoie lesURI à partir desquels nous avons reçu la réponse.

Parfois, il peut être différent deURI dans l'objet de requête, car une redirection peut se produire:

assertThat(request.uri()
  .toString(), equalTo("http://stackoverflow.com"));
assertThat(response.uri()
  .toString(), equalTo("https://stackoverflow.com/"));

7.2. En-têtes de la réponse

Nous pouvons obtenir les en-têtes de la réponse en appelant la méthodeheaders() sur un objet de réponse:

HttpResponse response = HttpClient.newHttpClient()
  .send(request, HttpResponse.BodyHandler.asString());
HttpHeaders responseHeaders = response.headers();

Il renvoie l'objetHttpHeaders comme type de retour. Il s'agit d'un nouveau type défini dans le packagejdk.incubator.http qui représente une vue en lecture seule des en-têtes HTTP.

Certaines méthodes utiles simplifient la recherche de la valeur des en-têtes.

7.3. Obtenir des remorques de la réponse

La réponse HTTP peut contenir des en-têtes supplémentaires qui sont inclus après le contenu de la réponse. Ces en-têtes sont appelés en-têtes de remorque.

On peut les obtenir en appelant la méthodetrailers() surHttpResponse:

HttpResponse response = HttpClient.newHttpClient()
  .send(request, HttpResponse.BodyHandler.asString());
CompletableFuture trailers = response.trailers();

Notez que la méthodetrailers() renvoie l'objetCompletableFuture.

7.4. Version de la réponse

La méthodeversion() définit quelle version du protocole HTTP a été utilisée pour parler avec un serveur.

N'oubliez pas que même si nous définissons que nous voulons utiliser HTTP / 2, le serveur peut répondre via HTTP / 1.1.

La version dans laquelle le serveur a répondu est spécifiée dans la réponse:

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))
  .version(HttpClient.Version.HTTP_2)
  .GET()
  .build();
HttpResponse response = HttpClient.newHttpClient()
  .send(request, HttpResponse.BodyHandler.asString());
assertThat(response.version(), equalTo(HttpClient.Version.HTTP_1_1));

8. Client Http Java 11

Le changement majeur de Java 11 a été la standardisation deHTTP client API that implements HTTP/2 and Web Socket.. Elle vise à remplacer l'ancienne classeHttpUrlConnection qui est présente dans le JDK depuis les toutes premières années de Java.

Le changement a été mis en œuvre dans le cadre du PEC 321.

8.1. Principaux changements dans le cadre du PEC 321

  1. L'API HTTP incubée de Java 9 est maintenant officiellement intégrée à l'API Java SE. Les nouveauxHTTP APIs se trouvent dansjava.net.HTTP. *

  2. La nouvelle version du protocole HTTP est conçue pour améliorer les performances globales de l'envoi de demandes par un client et de la réception de réponses du serveur. Ceci est réalisé en introduisant un certain nombre de modifications telles que le multiplexage de flux, la compression d'en-tête et les promesses de diffusion.

  3. Depuis Java 11, les appels asynchrones dethe API is now fully asynchronous (the previous HTTP/1.1 implementation was blocking). sont implémentés en utilisantCompletableFuture. L'implémentation deCompletableFuture prend soin d'appliquer chaque étape une fois la précédente terminée, donc tout ce flux est asynchrone.

  4. La nouvelle API client HTTP fournit un moyen standard d'effectuer des opérations réseau HTTP avec la prise en charge des fonctionnalités Web modernes telles que HTTP / 2, sans qu'il soit nécessaire d'ajouter des dépendances tierces.

  5. Les nouvelles API fournissent un support natif pour HTTP 1.1 / 2 WebSocket. Les classes principales et l’interface fournissant la fonctionnalité principale incluent:

    • LesHttpClient class, java.net.http.HttpClient

    • La classeHttpRequest,java.net.http.HttpRequest

    • L'interfaceHttpResponse , java.net.http.HttpResponse

    • L'interfaceWebSocket,java.net.http.WebSocket

8.2. Problèmes avec le client HTTP antérieur à Java 11

L'APIHttpURLConnection existante et son implémentation avaient de nombreux problèmes:

  • URLConnectionAPI a été conçu avec plusieurs protocoles qui ne fonctionnent plus (FTP, Gopher, etc.).

  • L'API est antérieure à HTTP / 1.1 et est trop abstraite.

  • Cela fonctionne uniquement en mode blocage (c’est-à-dire un thread par requête / réponse).

  • C'est très difficile à maintenir.

9. Changements dans le client HTTP avec Java 11

9.1. Introduction des classes d'usine statiques

De nouvelles classes d'usine statiquesBodyPublishers,BodySubscribers etBodyHandlers  sont introduites qui incluent les implémentations existantes deBodyPublisher,BodySubscriber etBodyHandler.

Ils sont utilisés pour effectuer des tâches courantes utiles, telles que la gestion du corps de la réponse sous forme de chaîne ou la diffusion du corps dans un fichier.

Par exemple dans Pre Java 11, nous devions faire quelque chose comme ceci:

HttpResponse response = client.send(request, HttpResponse.BodyHandler.asString());

Ce que nous pouvons maintenant simplifier en tant que:

HttpResponse response = client.send(request, BodyHandlers.ofString());

En outre, le nom des méthodes statiques a été normalisé pour plus de clarté.

Par exemple Les noms de méthodes commefromXxx sont utilisés lorsque nous les utilisons comme adaptateurs ou des noms commeofXxx lorsque nous créons des gestionnaires / abonnés prédéfinis.

9.2. Méthodes courantes pour les types de corps courants

Des méthodes d'usine pratiques pour les éditeurs créés et les gestionnaires pour la gestion des types de corps courants ont été introduites.

Par exemple Nous avons ci-dessous des méthodes fluides pour créer des éditeurs à partir d'octets, de fichiers et de chaînes:

BodyPublishers.ofByteArray
BodyPublishers.ofFile
BodyPublishers.ofString

De même, pour créer des gestionnaires à partir de ces types de corps courants, nous pouvons utiliser:

BodyHandlers.ofByteArray
BodyHandlers.ofString
BodyHandlers.ofFile

9.3. Autres modifications de l'API

1. Avec cette nouvelle API, nous utiliseronsBodyHandlers.discarding() etBodyHandlers.replacing(value) au lieu dediscard(Object replacement):

HttpResponse response1 = HttpClient.newHttpClient()
            .send(request, BodyHandlers.discarding());
HttpResponse response1 = HttpClient.newHttpClient()
            .send(request, BodyHandlers.replacing(value));

2. La nouvelle méthodeofLines() dans[.typeNameLabel]#BodyHandlers #is added to gère la diffusion en continu du corps de la réponse sous forme de flux de lignes.

3. La méthodefromLineSubscriber est ajoutée dansBodyHandlers class that can be used as an adapter between a BodySubscriber and a text-based Flow.Subscriber that parses text line by line.

4. Ajout d'un nouveauBodySubscriber.mapping dans la classeBodySubscribers qui peut être utilisé pour le mappage d'un type de corps de réponse à un autre en appliquant la fonction donnée à l'objet corps.

5. DansHttpClient.Redirect, les constantes d'énumérationSAME_PROTOCOL et la stratégieSECURE sont remplacées par une nouvelle énumérationNORMAL.

10. Gestion des promesses push dans HTTP / 2

Le nouveau client Http prend en charge les promesses push via l'interfacePushPromiseHandler

Il permet au serveur de «pousser» le contenu vers les ressources supplémentaires du client tout en demandant la ressource principale, économisant ainsi plus d'aller-retour et par conséquent, améliore les performances de rendu des pages.

C'est vraiment la fonctionnalité de multiplexage de HTTP / 2 qui nous permet d'oublier le regroupement des ressources. Pour chaque ressource, le serveur envoie une demande spéciale, appelée promesse push au client.

Les promesses push reçues, le cas échéant, sont gérées par lesPushPromiseHandler donnés. Une valeur nulle PushPromiseHnadler rejette toute promesse de push.

LeHttpClient a une méthodesendAsync surchargée qui nous permet de gérer de telles promesses, comme indiqué dans l'exemple ci-dessous.

Commençons par créer unPushPromiseHandler:

private static PushPromiseHandler pushPromiseHandler() {
    return (HttpRequest initiatingRequest,
        HttpRequest pushPromiseRequest,
        Function,
        CompletableFuture>> acceptor) -> {
        acceptor.apply(BodyHandlers.ofString())
            .thenAccept(resp -> {
                System.out.println(" Pushed response: " + resp.uri() + ", headers: " + resp.headers());
            });
        System.out.println("Promise request: " + pushPromiseRequest.uri());
        System.out.println("Promise request: " + pushPromiseRequest.headers());
    };
}

Ensuite, utilisons la méthodesendAsync pour gérer cette promesse push:

httpClient.sendAsync(pageRequest, BodyHandlers.ofString(), pushPromiseHandler())
    .thenAccept(pageResponse -> {
        System.out.println("Page response status code: " + pageResponse.statusCode());
        System.out.println("Page response headers: " + pageResponse.headers());
        String responseBody = pageResponse.body();
        System.out.println(responseBody);
    })
    .join();

11. Conclusion

Dans cet article, nous avons exploré l'APIHttpClient de Java 9, qui offre beaucoup de flexibilité et des fonctionnalités puissantes. Le code complet utilisé pour l’API HttpClient de Java 9 est disponibleover on GitHub.

Nous avons également exploré la nouvelle version de Java 11 HttpClient, qui a normalisé l'incubation de HttpClient introduite dans Java 9 avec des modifications plus puissantes. Les extraits de code utilisés pour Java 11 Http Client sont égalementavailable over Github.

Remarque: Dans les exemples, nous avons utilisé des exemples de points de terminaison REST fournis parhttps://postman-echo.com.