Faire une simple requête HTTP en Java

1. Vue d'ensemble

Dans ce rapide didacticiel, nous présentons un moyen d'exécuter des requêtes HTTP en Java - en utilisant la classe Java intégrée HttpUrlConnection.

Notez qu'à partir de JDK 11, Java fournit une nouvelle API pour effectuer des requêtes HTTP, qui est destinée à remplacer HttpUrlConnection, l' API HttpClient .

2. HttpUrlConnection

La classe HttpUrlConnection nous permet d' effectuer des requêtes HTTP de base sans utiliser de bibliothèques supplémentaires. Toutes les classes dont nous avons besoin font partie du package java.net .

Les inconvénients de l'utilisation de cette méthode sont que le code peut être plus lourd que les autres bibliothèques HTTP et qu'il ne fournit pas de fonctionnalités plus avancées telles que des méthodes dédiées pour l'ajout d'en-têtes ou l'authentification.

3. Création d'une demande

Nous pouvons créer une instance HttpUrlConnection en utilisant la méthode openConnection () de la classe URL . Notez que cette méthode crée uniquement un objet de connexion mais n'établit pas encore la connexion.

La classe HttpUrlConnection est utilisée pour tous les types de requêtes en définissant l' attribut requestMethod sur l'une des valeurs: GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE.

Créons une connexion à une URL donnée en utilisant la méthode GET:

URL url = new URL("//example.com"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET");

4. Ajout de paramètres de demande

Si nous voulons ajouter des paramètres à une requête, nous devons définir la propriété doOutput sur true , puis écrire une chaîne de la forme param1 = valeur¶m2 = valeur dans OutputStream de l' instance HttpUrlConnection :

Map parameters = new HashMap(); parameters.put("param1", "val"); con.setDoOutput(true); DataOutputStream out = new DataOutputStream(con.getOutputStream()); out.writeBytes(ParameterStringBuilder.getParamsString(parameters)); out.flush(); out.close();

Pour faciliter la transformation du paramètre Map , nous avons écrit une classe utilitaire appelée ParameterStringBuilder contenant une méthode statique, getParamsString () , qui transforme une Map en une String du format requis:

public class ParameterStringBuilder { public static String getParamsString(Map params) throws UnsupportedEncodingException{ StringBuilder result = new StringBuilder(); for (Map.Entry entry : params.entrySet()) { result.append(URLEncoder.encode(entry.getKey(), "UTF-8")); result.append("="); result.append(URLEncoder.encode(entry.getValue(), "UTF-8")); result.append("&"); } String resultString = result.toString(); return resultString.length() > 0 ? resultString.substring(0, resultString.length() - 1) : resultString; } }

5. Définition des en-têtes de demande

L'ajout d'en-têtes à une requête peut être réalisé en utilisant la méthode setRequestProperty () :

con.setRequestProperty("Content-Type", "application/json");

Pour lire la valeur d'un en-tête à partir d'une connexion, nous pouvons utiliser la méthode getHeaderField () :

String contentType = con.getHeaderField("Content-Type");

6. Configuration des délais d'expiration

La classe HttpUrlConnection permet de définir les délais de connexion et de lecture. Ces valeurs définissent l'intervalle de temps d'attente pour que la connexion au serveur soit établie ou que les données soient disponibles pour la lecture.

Pour définir les valeurs de délai d'attente, nous pouvons utiliser les méthodes setConnectTimeout () et setReadTimeout () :

con.setConnectTimeout(5000); con.setReadTimeout(5000);

Dans l'exemple, nous définissons les deux valeurs de délai d'expiration sur cinq secondes.

7. Manipulation des cookies

Le package java.net contient des classes qui facilitent l'utilisation des cookies tels que CookieManager et HttpCookie .

Tout d'abord, pour lire les cookies à partir d'une réponse , nous pouvons récupérer la valeur de l'en - tête Set-Cookie et l'analyser en une liste d' objets HttpCookie :

String cookiesHeader = con.getHeaderField("Set-Cookie"); List cookies = HttpCookie.parse(cookiesHeader);

Ensuite, nous ajouterons les cookies au magasin de cookies :

cookies.forEach(cookie -> cookieManager.getCookieStore().add(null, cookie));

Vérifions si un cookie appelé nom d'utilisateur est présent, et sinon, nous l'ajouterons au magasin de cookies avec une valeur de «john»:

Optional usernameCookie = cookies.stream() .findAny().filter(cookie -> cookie.getName().equals("username")); if (usernameCookie == null) { cookieManager.getCookieStore().add(null, new HttpCookie("username", "john")); }

Enfin, pour ajouter les cookies à la demande , nous devons définir l'en- tête Cookie , après la fermeture et la réouverture de la connexion:

con.disconnect(); con = (HttpURLConnection) url.openConnection(); con.setRequestProperty("Cookie", StringUtils.join(cookieManager.getCookieStore().getCookies(), ";"));

8. Gestion des redirections

Nous pouvons activer ou désactiver automatiquement les redirections suivantes pour une connexion spécifique en utilisant la méthode setInstanceFollowRedirects () avec le paramètre true ou false :

con.setInstanceFollowRedirects(false);

Il est également possible d' activer ou de désactiver la redirection automatique pour toutes les connexions :

HttpUrlConnection.setFollowRedirects(false);

Par défaut, le comportement est activé.

Lorsqu'une requête renvoie un code de statut 301 ou 302, indiquant une redirection, nous pouvons récupérer l'en- tête Location et créer une nouvelle requête vers la nouvelle URL:

if (status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM) { String location = con.getHeaderField("Location"); URL newUrl = new URL(location); con = (HttpURLConnection) newUrl.openConnection(); }

9. Lecture de la réponse

La lecture de la réponse à la demande peut être effectuée en analysant le InputStream de l' instance HttpUrlConnection .

Pour exécuter la demande, nous pouvons utiliser la getResponseCode () , connect () , getInputStream () ou getOutputStream () méthodes :

int status = con.getResponseCode();

Enfin, lisons la réponse de la requête et placez-la dans une chaîne de contenu :

BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream())); String inputLine; StringBuffer content = new StringBuffer(); while ((inputLine = in.readLine()) != null) { content.append(inputLine); } in.close();

Pour fermer la connexion , nous pouvons utiliser la méthode disconnect () :

con.disconnect(); 

10. Lecture de la réponse aux demandes échouées

Si la demande échoue, essayer de lire le InputStream de l' instance HttpUrlConnection ne fonctionnera pas. Au lieu de cela, nous pouvons consommer le flux fourni par HttpUrlConnection.getErrorStream () .

We can decide which InputStream to use by comparing the HTTP status code:

int status = con.getResponseCode(); Reader streamReader = null; if (status > 299) { streamReader = new InputStreamReader(con.getErrorStream()); } else { streamReader = new InputStreamReader(con.getInputStream()); }

And finally, we can read the streamReader in the same way as the previous section.

11. Building the Full Response

It's not possible to get the full response representation using the HttpUrlConnection instance.

However, we can build it using some of the methods that the HttpUrlConnection instance offers:

public class FullResponseBuilder { public static String getFullResponse(HttpURLConnection con) throws IOException { StringBuilder fullResponseBuilder = new StringBuilder(); // read status and message // read headers // read response content return fullResponseBuilder.toString(); } }

Here, we're reading the parts of the responses, including the status code, status message and headers, and adding these to a StringBuilder instance.

First, let's add the response status information:

fullResponseBuilder.append(con.getResponseCode()) .append(" ") .append(con.getResponseMessage()) .append("\n");

Ensuite, nous obtiendrons les en-têtes en utilisant getHeaderFields () et ajouterons chacun d'eux à notre StringBuilder au format HeaderName: HeaderValues :

con.getHeaderFields().entrySet().stream() .filter(entry -> entry.getKey() != null) .forEach(entry -> { fullResponseBuilder.append(entry.getKey()).append(": "); List headerValues = entry.getValue(); Iterator it = headerValues.iterator(); if (it.hasNext()) { fullResponseBuilder.append(it.next()); while (it.hasNext()) { fullResponseBuilder.append(", ").append(it.next()); } } fullResponseBuilder.append("\n"); });

Enfin, nous lirons le contenu de la réponse comme nous l'avons fait précédemment et l'ajouterons.

Notez que la méthode getFullResponse validera si la requête a réussi ou non afin de décider si elle doit utiliser con.getInputStream () ou con.getErrorStream () pour récupérer le contenu de la requête.

12. Conclusion

Dans cet article, nous avons montré comment nous pouvons effectuer des requêtes HTTP à l'aide de la classe HttpUrlConnection .

Le code source complet des exemples est disponible à l'adresse over sur GitHub.