Führen Sie eine einfache HTTP-Anforderung in Java durch

1. Übersicht

In diesem kurzen Tutorial stellen wir eine Möglichkeit vor, HTTP-Anforderungen in Java auszuführen - mithilfe der integrierten Java-Klasse HttpUrlConnection.

Beachten Sie, dass Java ab JDK 11 eine neue API zum Ausführen von HTTP-Anforderungen bereitstellt, die als Ersatz für die HttpUrlConnection, die HttpClient- API, gedacht ist .

2. HttpUrlConnection

Mit der HttpUrlConnection- Klasse können wir grundlegende HTTP-Anforderungen ohne Verwendung zusätzlicher Bibliotheken ausführen. Alle Klassen, die wir benötigen, sind Teil des java.net- Pakets.

Die Nachteile dieser Methode bestehen darin, dass der Code umständlicher sein kann als andere HTTP-Bibliotheken und keine erweiterten Funktionen wie dedizierte Methoden zum Hinzufügen von Headern oder zur Authentifizierung bietet.

3. Erstellen einer Anfrage

Wir können eine HttpUrlConnection- Instanz mit der openConnection () -Methode der URL- Klasse erstellen . Beachten Sie, dass diese Methode nur ein Verbindungsobjekt erstellt, die Verbindung jedoch noch nicht herstellt.

Die HttpUrlConnection- Klasse wird für alle Arten von Anforderungen verwendet, indem das requestMethod- Attribut auf einen der folgenden Werte gesetzt wird: GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE.

Stellen Sie mit der GET-Methode eine Verbindung zu einer bestimmten URL her:

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

4. Anforderungsparameter hinzufügen

Wenn wir einer Anforderung Parameter hinzufügen möchten, müssen wir die Eigenschaft doOutput auf true setzen und dann einen String der Form param1 = value¶m2 = value in den OutputStream der HttpUrlConnection- Instanz schreiben :

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

Um die Transformation des Parameters Map zu erleichtern , haben wir eine Dienstprogrammklasse namens ParameterStringBuilder geschrieben, die eine statische Methode, getParamsString () , enthält, die eine Map in einen String des erforderlichen Formats transformiert :

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. Anforderungsheader festlegen

Das Hinzufügen von Headern zu einer Anforderung kann mithilfe der setRequestProperty () -Methode erreicht werden:

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

Um den Wert eines Headers aus einer Verbindung zu lesen, können Sie die Methode getHeaderField () verwenden:

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

6. Zeitüberschreitungen konfigurieren

Mit der HttpUrlConnection- Klasse können Sie die Zeitüberschreitungen für das Verbinden und Lesen festlegen. Diese Werte definieren das Zeitintervall, in dem darauf gewartet werden soll, dass die Verbindung zum Server hergestellt wird oder Daten zum Lesen verfügbar sind.

Um die Timeout-Werte festzulegen , können Sie die Methoden setConnectTimeout () und setReadTimeout () verwenden:

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

Im Beispiel setzen wir beide Timeout-Werte auf fünf Sekunden.

7. Umgang mit Cookies

Das java.net- Paket enthält Klassen, die das Arbeiten mit Cookies wie CookieManager und HttpCookie erleichtern .

Um die Cookies aus einer Antwort zu lesen , können wir zunächst den Wert des Set-Cookie- Headers abrufen und in eine Liste von HttpCookie- Objekten analysieren :

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

Als nächstes werden wir die Cookies zum Cookie-Shop hinzufügen :

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

Überprüfen wir, ob ein Cookie mit dem Namen Benutzername vorhanden ist. Wenn nicht, fügen wir es dem Cookie-Speicher mit dem Wert "john" hinzu:

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

Um die Cookies zur Anfrage hinzuzufügen , müssen wir nach dem Schließen und erneuten Öffnen der Verbindung den Cookie- Header setzen :

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

8. Umgang mit Weiterleitungen

Mit der Methode setInstanceFollowRedirects () mit den Parametern true oder false können wir folgende Weiterleitungen für eine bestimmte Verbindung automatisch aktivieren oder deaktivieren :

con.setInstanceFollowRedirects(false);

Es ist auch möglich, die automatische Umleitung für alle Verbindungen zu aktivieren oder zu deaktivieren :

HttpUrlConnection.setFollowRedirects(false);

Standardmäßig ist das Verhalten aktiviert.

Wenn eine Anfrage einen Statuscode 301 oder 302 zurückgibt, der eine Umleitung anzeigt, können wir den Standortheader abrufen und eine neue Anfrage an die neue URL erstellen:

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. Lesen der Antwort

Das Lesen der Antwort der Anforderung kann durch Analysieren des InputStream der HttpUrlConnection- Instanz erfolgen.

Um die Anforderung auszuführen, können wir die Methoden getResponseCode () , connect () , getInputStream () oder getOutputStream () verwenden :

int status = con.getResponseCode();

Lassen Sie uns abschließend die Antwort der Anfrage lesen und in eine Inhaltszeichenfolge einfügen:

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

Um die Verbindung zu schließen , können wir die Methode connectect () verwenden:

con.disconnect(); 

10. Lesen der Antwort auf fehlgeschlagene Anforderungen

Wenn die Anforderung fehlschlägt, funktioniert der Versuch, den InputStream der HttpUrlConnection- Instanz zu lesen, nicht. Stattdessen können wir den von HttpUrlConnection.getErrorStream () bereitgestellten Stream verwenden .

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

Als Nächstes rufen wir die Header mit getHeaderFields () ab und fügen sie im Format HeaderName: HeaderValues : zu unserem StringBuilder hinzu .

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"); });

Schließlich lesen wir den Antwortinhalt wie zuvor und hängen ihn an.

Beachten Sie, dass die getFullResponse- Methode überprüft , ob die Anforderung erfolgreich war oder nicht, um zu entscheiden, ob con.getInputStream () oder con.getErrorStream () zum Abrufen des Inhalts der Anforderung verwendet werden muss.

12. Schlussfolgerung

In diesem Artikel haben wir gezeigt, wie wir HTTP-Anforderungen mit der HttpUrlConnection- Klasse ausführen können .

Den vollständigen Quellcode der Beispiele finden Sie auf GitHub.