5 Möglichkeiten für HTTP-Anfragen in Java
Lesezeit: 5 Minuten
[Quelle des Bilds aus der Überschrift: Iron in the Butterfly Nebula, NASA Astronomy Picture of the Day, 21. Juli 2020 (angepasst)]
Das Durchführen von HTTP-Anfragen ist eine der wichtigsten Aufgaben des modernen Programmierens. Beim Erlernen einer neuen Programmiersprache gehören HTTP-Anfragen oft zu den Dingen, mit denen man sich als Erstes befasst. Java-Programmierern stehen dazu viele Möglichkeiten zur Verfügung – JDK-Kernbibliotheken sowie auch Bibliotheken von Drittanbietern. In diesem Blog stelle ich meine bevorzugten Java HTTP-Clients vor. Wenn ihr andere verwendet, ist das auch gut! Erzählt mir gerne, welches eure Favoriten sind. In diesem Blog gehe ich auf folgende Themen ein:
CORE JAVA:
- HttpURLConnection
- HttpClient
BELIEBTE BIBLIOTHEKEN:
- ApacheHttpClient
- OkHttp
- Retrofit
Für die Codebeispiele werde ich die API Astronomy Picture of the Day aus dem NASA API-Portal nutzen, und der Code an sich ist komplett auf GitHub zu finden, in einem auf Java 11 basierten Projekt.
Core Java-APIs für das Stellen von HTTP-Anfragen
Seit Java 1.1 enthalten die Kernbibliotheken aus dem JDK einen HTTP-Client. In Java 11 ist ein neuer Client hinzugekommen. Einer dieser beiden Clients könnte eine gute Option sein, wenn uns das Hinzufügen zusätzlicher Abhängigkeiten zu einem Projekt Sorgen bereitet.
Java 1.1 HttpURLConnection
Gleich zu Beginn die große Frage: Sollen Akronyme in Class-Namen nun groß oder klein geschrieben werden? Wichtig ist, dass wir konsistent vorgehen. Wie auch immer, wir schließen nun unsere Augen und versetzen uns ins Jahr 1997 zurück. „Titanic“ brach im Kino alle Kassenrekorde und inspirierte Tausende von Memes, und die Spice Girls eroberten mit ihrem Bestseller-Album die Charts. Das zweifellos wichtigste Ereignis des Jahres war jedoch, dass Java 1.1 um HttpURLConnection erweitert wurde. Hier zeige ich euch nun, wie wir mit HttpURLConnection eine GET
-Anfrage stellen, um die APOD-Daten abzurufen:
[vollständiger Code auf GitHub]
Das Ganze wirkt vergleichsweise umständlich, und die Reihenfolge der Aktionen ist verwirrend (warum werden die Header beispielsweise nach dem Öffnen der URL festgelegt?). Komplexere Anfragen mit POST
-Bodies bzw. benutzerdefinierte Timeouts usw. sind zwar möglich, aber aus meiner Sicht ist diese API überhaupt nicht intuitiv.
Wofür würde man HttpURLConnection
also eigentlich nutzen? Für alle, die Clients mit älteren Java-Versionen unterstützen und keine Abhängigkeit hinzufügen können, ist HttpURLConnection eventuell eine gute Wahl. Ich vermute, dass dies nur eine kleine Minderheit von Entwicklern betrifft, aber in älteren Setups stößt man vielleicht noch auf diese Codebasis. Wer Interesse an moderneren Ansätzen hat, sollte weiterlesen.
Java 11 HttpClient
Mehr als 20 Jahre nach der Einführung von HttpURLConnection
stürmte Black Panther in die Kinocharts, und Java 11 wurde um einen neuen HTTP-Client bereichert: java.net.http.HttpClient
. Dieser zeichnet sich durch eine deutlich logischere API aus und kann nicht nur HTTP/2, sondern auch Websockets verarbeiten. Zudem bietet er die Möglichkeit, über die API CompletableFuture
synchrone oder asynchrone Anfragen zu stellen.
Bei HTTP-Anfragen möchte ich in 99 von 100 Fällen in der Lage sein, den Response-Body in meinen Code auszulesen. Wenn eine Bibliothek dies nicht leicht möglich macht, kommt bei mir keine Freude auf. HttpClient akzeptiert einen BodyHandler
, mit dem eine HTTP-Response in eine Klasse unserer Wahl umgewandelt werden kann. Es gibt integrierte Handler: String
, byte[]
für binäre Daten, Stream<String>
zum Aufteilen nach Zeilen sowie einige andere. Wir können aber auch eigene Handler definieren. Und das kann sich als hilfreich erweisen, weil es zum Beispiel keinen integrierten BodyHandler
für das Parsen von JSON gibt. Ich habe (hier) mit Jackson gemäß einem Beispiel aus Java Docs einen solchen Handler geschrieben. Der Code gibt einen Supplier
für die APOD-Klasse zurück, d. h. wir führen .get()
aus, wenn wir das Ergebnis abrufen wollen.
Das hier ist eine synchrone Anfrage:
Bei einer asynchronen Anfrage werden client
und request
auf dieselbe Art ausgeführt, und anschließend verwenden wir den Befehl .sendAsync
statt .send
:
[vollständiger Code auf GitHub]
Java HTTP-Client-Bibliotheken von Drittanbietern
Keine Sorge, falls die integrierten Clients für eure Zwecke nicht geeignet sind! Es gibt jede Menge Bibliotheken, mit denen ihr die für euer spezifisches Projekt nötigen Aufgaben erledigen könnt.
Apache HttpClient
Die Apache Software Foundation HTTP-Clients gibt es bereits seit geraumer Zeit. Sie sind weit verbreitet und bilden die Grundlage vieler High-Level-Bibliotheken. Ihre Geschichte ist ein wenig verwirrend. Der alte Commons HttpClient wird nicht weiterentwickelt, und die neue Version (ebenfalls HttpClient genannt), läuft unter dem HttpComponents-Projekt. Version 5.0 wurde Anfang 2020 veröffentlicht und bietet nun Unterstützung für HTTP/2. Die Bibliothek unterstützt sowohl synchrone als auch asynchrone Anfragen.
Insgesamt handelt es sich eher um eine Low-Level-API, d. h., wir müssen viel selbst implementieren. Mit dem folgenden Code wird die NASA-API aufgerufen. Die Verwendung ist nicht allzu schwierig, aber ich habe die Fehlerbehandlung, die bei Produktionscode nötig wäre, größtenteils übersprungen. Und auch hier musste ich Jackson-Code verwenden, um die JSON-Antwort zu parsen. Eventuell empfiehlt es sich auch, ein Logging-Framework zu konfigurieren, um stdout-Warnungen zu vermeiden (eigentlich keine große Sache, aber doch irgendwie ärgerlich). Der Code sieht jedenfalls so aus:
[vollständiger Code auf GitHub]
Apache bietet zahlreiche weitere Beispiele für Anfragen des Typs sync und async (synchrone und asynchrone Anfragen).
OkHttp
OkHttp ist ein HTTP-Client von Square mit vielen nützlichen integrierten Funktionen, darunter die automatische Verarbeitung von GZIP, Antwort-Caching, erneute Versuche oder Fallbacks auf andere Hosts bei Netzwerkfehlern sowie Unterstützung für HTTP/2 und WebSocket. Die API ist gut strukturiert, allerdings gibt es keine integrierte Funktion zum Parsen von JSON-Antworten, daher habe ich auch hier wieder über Jackson Code zum Parsen von JSON hinzugefügt:
[vollständiger Code auf GitHub]
Das passt also, aber die wahre Leistung von OkHttp wird erst klar, wenn man es mit Retrofit kombiniert.
Retrofit
Retrofit ist eine weitere Bibliothek von Square, die auf OkHttp aufbaut. In Kombination mit den Low-Level-Funktionen von OkHttp bietet Retrofit die Möglichkeit, Java-Klassen zu erstellen. Dabei werden die HTTP-Details extrahiert, und es ergibt sich daraus eine nette Java-freundliche API.
Als Erstes müssen wir eine Schnittstelle erstellen, die deklariert, welche Methoden für den Aufruf an die APOD-API verwendet werden sollen. Anhand von Annotationen wird definiert, welchen HTTP-Anfragen sie entsprechen:
Der Rückgabetyp CompletableFuture<APOD>
zeigt an, dass es sich hier um einen asynchronen Client handelt. Square stellt weitere Adapter bereit, wir können aber auch einen eigenen programmieren. Eine Schnittstelle wie diese hilft, den Client für Tests zu simulieren, und das gefällt mir gut.
Nach dem Deklarieren der Schnittstelle weisen wir Retrofit an, eine Implementierung zu erstellen, mit der wir Anfragen für eine bestimmte Basis-URL stellen können. Bei Integrationstests ist es praktisch, dass man die Basis-URL wechseln kann. Der Code, mit dem wir den Client generieren, sieht wie folgt aus:
[vollständiger Code auf GitHub]
API-Authentifizierung
Falls für unsere Schnittstelle mehrere Methoden existieren, die alle einen API-Schlüssel benötigen, können wir dies konfigurieren, indem wir dem zugrundeliegenden OkHttpClient
einen HttpInterceptor
hinzufügen. Der benutzerdefinierte Client kann dem Retrofit.Builder
hinzugefügt werden. Der Code zum Erstellen des benutzerdefinierten Client sieht wie folgt aus:
[vollständiger Code auf GitHub]
Außer für die ganz einfachen Szenarien gefällt mir diese Art von Java-API sehr gut. Klassen zu entwerfen, die Remote-APIs verkörpern, ist eine nette Abstraktion, die sich auch gut mit Dependency Injection kombinieren lässt. Und es ist wirklich genial, dass Retrofit diese Klassen auf der Basis eines anpassbaren OkHttp-Clients für uns erstellt.
Weitere HTTP-Clients für Java
Ich habe diesen Blog auf Twitter geteilt und mich sehr über die rege Diskussion zu HTTP-Clients gefreut, die sich daraus ergeben hat. Sollten die oben erwähnten Optionen nicht ganz euer Fall sein, werft einfach einen Blick auf diese Vorschläge:
- REST Assured – ein HTTP-Client, der auf das Testen von REST-Services ausgelegt ist. Er bietet eine sogenannte Fluent Interface für das Stellen von Anfragen sowie hilfreiche Methoden, um Behauptungen zu Antworten aufzustellen.
- cvurl – ein Wrapper für den Java 11 HttpClient, der bei komplexeren Anfragen einige der Herausforderungen beseitigt.
- Feign – ähnlich wie Retrofit kann auch Feign anhand annotierter Schnittstellen Klassen erstellen. Feign ist sehr flexibel und bietet verschiedene Optionen zum Erstellen und Auslesen von Anfragen, Kennzahlen, erneuten Versuchen u. v. m.
- Spring RestTemplate (synchrone) und WebClient (asynchrone) Clients – wer Spring für alle Teile seines Projekts verwendet hat, sollte konsequent bei diesem Ökosystem bleiben. Baeldung vergleicht die beiden Clients in einem Artikel.
- MicroProfile Rest Client – ein weiterer Client des Typs „Erstellen einer Klasse anhand einer annotierten Schnittstelle“. Dieser Client ist insofern interessant, weil man über die gleiche Schnittstelle auch einen Web-Server erstellen kann. So hat man die Gewissheit, dass Client und Server aufeinander abgestimmt sind. Wenn wir also für einen bestimmten Dienst sowohl einen Server als auch einen Client erstellen wollen, könnte dies eine gute Option sein.
Zusammenfassung
Bei der Java-Entwicklung steht eine große Auswahl an HTTP-Clients zur Verfügung. Für einfache Entwicklungsszenarien würde ich den integrierten java.net.http.HttpClient
empfehlen. Für komplexere Anwendungsfälle oder wenn die HTTP-APIs als Teil einer größeren Anwendung als Java-Klassen abstrahiert werden soll, bietet sich Retrofit oder Feign an. Viel Spaß beim Programmieren, ich bin gespannt auf eure Ergebnisse!
📧 mgilliard@twilio.com
Verwandte Posts
Ähnliche Ressourcen
Twilio Docs
Von APIs über SDKs bis hin zu Beispiel-Apps
API-Referenzdokumentation, SDKs, Hilfsbibliotheken, Schnellstarts und Tutorials für Ihre Sprache und Plattform.
Ressourcen-Center
Die neuesten E-Books, Branchenberichte und Webinare
Lernen Sie von Customer-Engagement-Experten, um Ihre eigene Kommunikation zu verbessern.
Ahoy
Twilios Entwickler-Community-Hub
Best Practices, Codebeispiele und Inspiration zum Aufbau von Kommunikations- und digitalen Interaktionserlebnissen.