Configuration avancée du client

Configuration avancée du client

1. Vue d'ensemble

Dans cet article, nous examinerons l'utilisation avancée de la bibliothèque ApacheHttpClient.

Nous examinerons les exemples d'ajout d'en-têtes personnalisés aux requêtes HTTP, et nous verrons comment configurer le client pour autoriser et envoyer des requêtes via un serveur proxy.

Nous allons utiliser Wiremock pour le stubbing du serveur HTTP. Si vous voulez en savoir plus sur Wiremock, consultezthis article.

2. Requête HTTP avec un en-têteUser-Agent personnalisé

Disons que nous voulons ajouter un en-têteUser-Agent personnalisé à une requête HTTP GET. L'en-têteUser-Agent contient une chaîne caractéristique qui permet aux homologues de protocole réseau d'identifier le type d'application, le système d'exploitation et le fournisseur ou la version logicielle de l'agent utilisateur logiciel demandeur.

Avant de commencer à écrire notre client HTTP, nous devons démarrer notre serveur fictif intégré:

@Rule
public WireMockRule serviceMock = new WireMockRule(8089);

Lorsque nous créons une instanceHttpGet, nous pouvons simplement utiliser une méthodesetHeader() pour passer un nom de notre en-tête avec la valeur. Cet en-tête sera ajouté à une requête HTTP:

String userAgent = "exampleAgent/1.0";
HttpClient httpClient = HttpClients.createDefault();

HttpGet httpGet = new HttpGet("http://localhost:8089/detail");
httpGet.setHeader(HttpHeaders.USER_AGENT, userAgent);

HttpResponse response = httpClient.execute(httpGet);

assertEquals(response.getStatusLine().getStatusCode(), 200);

Nous ajoutons un en-têteUser-Agent et envoyons cette requête via une méthodeexecute().

Lorsque la requête GET est envoyée pour une URL/detail avec en-têteUser-Agent qui a une valeur égale à «exampleAgent / 1.0», alorsserviceMock renverra 200 code de réponse HTTP:

serviceMock.stubFor(get(urlEqualTo("/detail"))
  .withHeader("User-Agent", equalTo(userAgent))
  .willReturn(aResponse().withStatus(200)));

3. Envoi de données dans le corps de la requête POST

Habituellement, lorsque nous exécutons la méthode HTTP POST, nous souhaitons transmettre une entité en tant que corps de requête. Lors de la création d'une instance d'un objetHttpPost, nous pouvons ajouter le corps à cette requête en utilisant une méthodesetEntity():

String xmlBody = "1";
HttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("http://localhost:8089/person");
httpPost.setHeader("Content-Type", "application/xml");

StringEntity xmlEntity = new StringEntity(xmlBody);
httpPost.setEntity(xmlEntity);

HttpResponse response = httpClient.execute(httpPost);

assertEquals(response.getStatusLine().getStatusCode(), 200);

Nous créons une instanceStringEntity avec un corps au formatXML. Il est important de définir l'en-têteContent-Type sur «application/xml» pour transmettre au serveur des informations sur le type de contenu que nous envoyons. Lorsque leserviceMock reçoit la requête POST avec le corps XML, il répond avec le code d'état 200 OK:

serviceMock.stubFor(post(urlEqualTo("/person"))
  .withHeader("Content-Type", equalTo("application/xml"))
  .withRequestBody(equalTo(xmlBody))
  .willReturn(aResponse().withStatus(200)));

4. Envoi de requêtes via un serveur proxy

Souvent, notre service Web peut êtrebehind a proxy server qui exécute une logique supplémentaire, met en cache des ressources statiques, etc. Lorsque nous créons le client HTTP et envoyons une requête à un service réel, nous ne voulons pas traiter cela sur chaque requête HTTP.

Pour tester ce scénario, nous devons démarrer un autre serveur Web intégré:

@Rule
public WireMockRule proxyMock = new WireMockRule(8090);

Avec deux serveurs intégrés, le premier service réel est sur le port 8089 et un serveur proxy est à l'écoute sur le port 8090.

Nous configurons nosHttpClient pour envoyer toutes les requêtes via un proxy en créant unDefaultProxyRoutePlanner qui prend le proxy d'instanceHttpHost comme argument:

HttpHost proxy = new HttpHost("localhost", 8090);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
HttpClient httpclient = HttpClients.custom()
  .setRoutePlanner(routePlanner)
  .build();

Notre serveur proxy redirige toutes les demandes vers le service réel qui écoute sur le port 8090. À la fin du test, nous vérifions que la demande a été envoyée à notre service actuel via un proxy:

proxyMock.stubFor(get(urlMatching(".*"))
  .willReturn(aResponse().proxiedFrom("http://localhost:8089/")));

serviceMock.stubFor(get(urlEqualTo("/private"))
  .willReturn(aResponse().withStatus(200)));

assertEquals(response.getStatusLine().getStatusCode(), 200);
proxyMock.verify(getRequestedFor(urlEqualTo("/private")));
serviceMock.verify(getRequestedFor(urlEqualTo("/private")));

5. Configuration du client HTTP pour autoriser via un proxy

En prolongeant l'exemple précédent, dans certains cas, le serveur proxy est utilisé pour effectuer une autorisation. Dans une telle configuration, un proxy peut autoriser toutes les demandes et les transmettre au serveur caché derrière un proxy.

Nous pouvons configurer le HttpClient pour envoyer chaque requête via un proxy, avec l'en-têteAuthorization qui sera utilisé pour effectuer un processus d'autorisation.

Supposons que nous ayons un serveur proxy qui n'autorise qu'un seul utilisateur - «username_admin», avec un mot de passe «secret_password».

Nous devons créer l'instanceBasicCredentialsProvider avec les informations d'identification de l'utilisateur qui sera autorisé via le proxy. Pour queHttpClient ajoute automatiquement l'en-têteAuthorization avec la valeur appropriée, nous devons créer unHttpClientContext avec les informations d'identification fournies et unBasicAuthCache qui stocke les informations d'identification:

HttpHost proxy = new HttpHost("localhost", 8090);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);

//Client credentials
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(proxy),
  new UsernamePasswordCredentials("username_admin", "secret_password"));

// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();

BasicScheme basicAuth = new BasicScheme();
authCache.put(proxy, basicAuth);
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credentialsProvider);
context.setAuthCache(authCache);

HttpClient httpclient = HttpClients.custom()
  .setRoutePlanner(routePlanner)
  .setDefaultCredentialsProvider(credentialsProvider)
  .build();

Lorsque nous configurons nosHttpClient,, faire des demandes à notre service entraînera l'envoi d'une demande via un proxy avec un en-têteAuthorization pour effectuer le processus d'autorisation. Il sera défini dans chaque demande automatiquement.

Exécutons une requête réelle au service:

HttpGet httpGet = new HttpGet("http://localhost:8089/private");
HttpResponse response = httpclient.execute(httpGet, context);

La vérification d'une méthodeexecute() sur lehttpClient avec notre configuration confirme qu'une requête est passée par un proxy avec un en-têteAuthorization:

proxyMock.stubFor(get(urlMatching("/private"))
  .willReturn(aResponse().proxiedFrom("http://localhost:8089/")));
serviceMock.stubFor(get(urlEqualTo("/private"))
  .willReturn(aResponse().withStatus(200)));

assertEquals(response.getStatusLine().getStatusCode(), 200);
proxyMock.verify(getRequestedFor(urlEqualTo("/private"))
  .withHeader("Authorization", containing("Basic")));
serviceMock.verify(getRequestedFor(urlEqualTo("/private")));

6. Conclusion

Cet article montre comment configurer ApacheHttpClient pour effectuer des appels HTTP avancés. Nous avons vu comment envoyer des demandes via un serveur proxy et comment autoriser via un proxy.

L'implémentation de tous ces exemples et extraits de code peut être trouvée dans leGitHub project - il s'agit d'un projet Maven, il devrait donc être facile à importer et à exécuter tel quel.