Esegui una semplice richiesta HTTP in Java

1. Panoramica

In questo breve tutorial, presentiamo un modo per eseguire richieste HTTP in Java , utilizzando la classe Java incorporata HttpUrlConnection.

Si noti che a partire da JDK 11, Java fornisce una nuova API per l'esecuzione di richieste HTTP, che è intesa come una sostituzione per HttpUrlConnection, l' API HttpClient .

2. HttpUrlConnection

La classe HttpUrlConnection ci consente di eseguire richieste HTTP di base senza l'utilizzo di librerie aggiuntive. Tutte le classi di cui abbiamo bisogno fanno parte del pacchetto java.net .

Gli svantaggi dell'utilizzo di questo metodo sono che il codice può essere più complicato di altre librerie HTTP e che non fornisce funzionalità più avanzate come metodi dedicati per l'aggiunta di intestazioni o autenticazione.

3. Creazione di una richiesta

Possiamo creare un'istanza HttpUrlConnection utilizzando il metodo openConnection () della classe URL . Si noti che questo metodo crea solo un oggetto connessione ma non stabilisce ancora la connessione.

La classe HttpUrlConnection viene utilizzata per tutti i tipi di richieste impostando l' attributo requestMethod su uno dei valori: GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE.

Creiamo una connessione a un determinato URL utilizzando il metodo GET:

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

4. Aggiunta di parametri di richiesta

Se vogliamo aggiungere parametri a una richiesta, dobbiamo impostare la doOutput proprietà su true , quindi scrivere una stringa della forma param1 = value¶m2 = valore al OutputStream del HttpURLConnection esempio:

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();

Per facilitare la trasformazione del parametro Map , abbiamo scritto una classe di utilità chiamata ParameterStringBuilder contenente un metodo statico, getParamsString () , che trasforma una Map in una String del formato richiesto:

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. Impostazione delle intestazioni delle richieste

L'aggiunta di intestazioni a una richiesta può essere ottenuta utilizzando il metodo setRequestProperty () :

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

Per leggere il valore di un'intestazione da una connessione, possiamo utilizzare il metodo getHeaderField () :

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

6. Configurazione dei timeout

La classe HttpUrlConnection consente di impostare i timeout di connessione e lettura. Questi valori definiscono l'intervallo di tempo di attesa prima che venga stabilita la connessione al server o che i dati siano disponibili per la lettura.

Per impostare i valori di timeout, possiamo usare i metodi setConnectTimeout () e setReadTimeout () :

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

Nell'esempio, impostiamo entrambi i valori di timeout su cinque secondi.

7. Gestione dei cookie

Il pacchetto java.net contiene classi che facilitano il lavoro con i cookie come CookieManager e HttpCookie .

Innanzitutto, per leggere i cookie da una risposta , possiamo recuperare il valore dell'intestazione Set-Cookie e analizzarlo in un elenco di oggetti HttpCookie :

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

Successivamente, aggiungeremo i cookie al negozio di cookie :

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

Controlliamo se è presente un cookie chiamato username e, in caso contrario, lo aggiungeremo al cookie store con un valore "john":

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

Infine, per aggiungere i cookie alla richiesta , occorre impostare l' intestazione Cookie , dopo aver chiuso e riaperto la connessione:

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

8. Gestione dei reindirizzamenti

Possiamo abilitare o disabilitare automaticamente i seguenti reindirizzamenti per una connessione specifica utilizzando il metodo setInstanceFollowRedirects () con il parametro true o false :

con.setInstanceFollowRedirects(false);

È anche possibile abilitare o disabilitare il reindirizzamento automatico per tutte le connessioni :

HttpUrlConnection.setFollowRedirects(false);

Per impostazione predefinita, il comportamento è abilitato.

Quando una richiesta restituisce un codice di stato 301 o 302, che indica un reindirizzamento, possiamo recuperare l' intestazione Location e creare una nuova richiesta per il nuovo 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. Leggere la risposta

Leggendo la risposta della richiesta può essere fatto analizzando l'InputStream del HttpURLConnection istanza.

Per eseguire la richiesta, siamo in grado di utilizzare il getResponseCode () , connect () , getInputStream () o getOutputStream () metodi :

int status = con.getResponseCode();

Infine, leggiamo la risposta della richiesta e inseriamola in una stringa di contenuto :

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

Per chiudere la connessione , possiamo usare il metodo disconnect () :

con.disconnect(); 

10. Lettura della risposta alle richieste non riuscite

Se la richiesta non riesce, cercando di leggere l'InputStream del HttpURLConnection istanza non funzionerà. Invece, siamo in grado di consumare il flusso fornito da 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");

Successivamente, otterremo le intestazioni utilizzando getHeaderFields () e le aggiungeremo ciascuna al nostro StringBuilder nel formato 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"); });

Infine, leggeremo il contenuto della risposta come abbiamo fatto in precedenza e lo aggiungeremo.

Si noti che il metodo getFullResponse convaliderà se la richiesta ha avuto successo o meno per decidere se è necessario utilizzare con.getInputStream () o con.getErrorStream () per recuperare il contenuto della richiesta.

12. Conclusione

In questo articolo, abbiamo mostrato come possiamo eseguire richieste HTTP usando la classe HttpUrlConnection .

Il codice sorgente completo degli esempi può essere trovato su GitHub.