HTTP-Anfragen mit Kotlin und khttp
1. Einführung
Das HTTP-Protokoll und die darauf aufbauenden APIs sind heutzutage von zentraler Bedeutung für die Programmierung.
In der JVM stehen verschiedene Optionen zur Verfügung, von Bibliotheken auf niedrigerer bis sehr hoher Ebene, von etablierten Projekten bis hin zu neuen Kindern im Block. Die meisten davon richten sich jedoch in erster Linie an Java-Programme.
In diesem Artikelwe’re going to look at khttp, an idiomatic Kotlin library for consuming HTTP-based resources und APIs.
2. Abhängigkeiten
Um die Bibliothek in unserem Projekt verwenden zu können, müssen wir sie zunächst zu unseren Abhängigkeiten hinzufügen:
khttp
khttp
0.1.0
Da dies noch nicht auf Maven Central ist, müssen wir auch das JCenter-Repository aktivieren:
central
http://jcenter.bintray.com
Version 0.1.0 ist die zum Zeitpunkt des Schreibens aktuelle. Wir können natürlichcheck JCenter for a newer one.
3. Grundsätzliche Verwendung
Die Grundlagen des HTTP-Protokolls sind einfach, auch wenn die Details sehr kompliziert sein können. Daher hat khttp auch eine einfache Oberfläche.
For every HTTP method, we can find a package-level function in the khttp package, wieget,post und so weiter.
Die Funktionen verwenden alle die gleichen Argumente und geben das ObjektResponsezurück. Einzelheiten dazu finden Sie in den folgenden Abschnitten.
Im Verlauf dieses Artikels verwenden wir das vollständig qualifizierte Formular, z. B.khttp.put. In unseren Projekten können wir natürlich diese Methoden importieren und möglicherweise umbenennen:
import khttp.delete as httpDelete
Note: we’ve added type declarations for clarity throughout code examples, da sie ohne IDE schwer zu verfolgen sein könnten.
4. Eine einfache Anfrage
Every HTTP request has at least two required components: a method and a URL. In khttp wird die Methode durch die von uns aufgerufene Funktion bestimmt, wie wir im vorherigen Abschnitt gesehen haben.
Die URL ist das einzige erforderliche Argument für die Methode. So können wir leicht eine einfache Anfrage durchführen:
khttp.get("http://httpbin.org/get")
In den folgenden Abschnitten werden alle Anforderungen berücksichtigt, um erfolgreich abgeschlossen zu werden.
4.1. Parameter hinzufügen
Insbesondere für GET-Anforderungen müssen häufig zusätzlich zur Basis-URL Abfrageparameter angegeben werden.
khttp’s methods accept a params argument ist einMap von Schlüssel-Wert-Paaren, die in die AbfrageString: aufgenommen werden sollen
khttp.get(
url = "http://httpbin.org/get",
params = mapOf("key1" to "value1", "keyn" to "valuen"))
Beachten Sie, dass wir die FunktionmapOf verwendet haben, um einMap im laufenden Betrieb zu erstellen. Die resultierende Anforderungs-URL lautet:
http://httpbin.org/get?key1=value1&keyn=valuen
5. Eine Anforderungsstelle
Eine weitere häufig auszuführende Operation ist das Senden von Daten, normalerweise als Nutzdaten einer POST- oder PUT-Anforderung.
Zu diesem Zweck bietet die Bibliothek verschiedene Optionen, die wir in den folgenden Abschnitten untersuchen werden.
5.1. Senden einer JSON-Nutzlast
We can use the json argument to send a JSON object or array. Es kann verschiedene Arten geben:
-
AJSONObject oderJSONArray, wie von der Bibliothek org.json bereitgestellt
-
AMap, das in ein JSON-Objekt umgewandelt wird
-
ACollection,Iterable oder Array, das in ein JSON-Array umgewandelt wird
Wir können unser früheres GET-Beispiel leicht in ein POST-Beispiel umwandeln, das ein einfaches JSON-Objekt sendet:
khttp.post(
url = "http://httpbin.org/post",
json = mapOf("key1" to "value1", "keyn" to "valuen"))
Beachten Sie, dass die Umwandlung von Auflistungen in JSON-Objekte flach ist. Beispielsweise werdenList vonMap nicht in ein JSON-Array von JSON-Objekten konvertiert, sondern in ein Array von Zeichenfolgen.
Für eine umfassende Konvertierung benötigen wir eine komplexere JSON-Zuordnungsbibliothek wie Jackson. Die Konvertierungsmöglichkeit der Bibliothek ist nur für einfache Fälle gedacht.
5.2. Senden von Formulardaten (URL-codiert)
Zum Senden von Formulardaten (URL-codiert wie in HTML-Formularen) verwenden wir das Argumentdata mit einemMap:
khttp.post(
url = "http://httpbin.org/post",
data = mapOf("key1" to "value1", "keyn" to "valuen"))
5.3. Hochladen von Dateien (mehrteiliges Formular)
Wir können eine oder mehrere Dateien senden, die als mehrteilige Formulardatenanforderung codiert sind.
In diesem Fall verwenden wir das Argumentfiles:
khttp.post(
url = "http://httpbin.org/post",
files = listOf(
FileLike("file1", "content1"),
FileLike("file2", File("kitty.jpg"))))
Wir können sehen, dass khttp eineFileLike-Abstraktion verwendet, bei der es sich um ein Objekt mit einem Namen und einem Inhalt handelt. Der Inhalt kann eine Zeichenfolge, ein Byte-Array, einFile oder einPath sein.
5.4. Senden von Rohinhalten
Wenn keine der oben genannten Optionen geeignet ist, können wirInputStream verwenden, um Rohdaten als Hauptteil einer HTTP-Anforderung zu senden:
khttp.post(url = "http://httpbin.org/post", data = someInputStream)
In diesem Fall müssen wir höchstwahrscheinlich auch einige Header manuell festlegen, die wir in einem späteren Abschnitt behandeln werden.
6. Umgang mit der Antwort
Bisher haben wir verschiedene Möglichkeiten zum Senden von Daten an einen Server gesehen. Viele HTTP-Vorgänge sind jedoch nützlich, da sie auch Daten zurückgeben.
khttp basiert auf dem Blockieren von E / A, daher enthältall functions corresponding to HTTP methods return a Response object die vom Server empfangene Antwort.
Dieses Objekt verfügt über verschiedene Eigenschaften, auf die wir je nach Art des Inhalts zugreifen können.
6.1. JSON-Antworten
Wenn wir wissen, dass die Antwort ein JSON-Objekt oder -Array ist, können wir die EigenschaftenjsonObject undjsonArrayverwenden:
val response : Response = khttp.get("http://httpbin.org/get")
val obj : JSONObject = response.jsonObject
print(obj["someProperty"])
6.2. Text oder binäre Antworten
Wenn wir die Antwort stattdessen alsString lesen möchten, können wir die Eigenschafttext verwenden:
val message : String = response.text
Oder wenn wir es als Binärdaten lesen möchten (z. einen Dateidownload) verwenden wir die Eigenschaftcontent:
val imageData : ByteArray = response.content
Schließlich können wir auch auf die zugrunde liegendenInputStream zugreifen:
val inputStream : InputStream = response.raw
7. Fortgeschrittene Nutzung
Schauen wir uns auch einige fortgeschrittenere Verwendungsmuster an, die im Allgemeinen nützlich sind und die wir in den vorherigen Abschnitten noch nicht behandelt haben.
7.1. Umgang mit Headern und Cookies
All khttp functions take a headers argument ist einMap der Headernamen und -werte.
val response = khttp.get(
url = "http://httpbin.org/get",
headers = mapOf("header1" to "1", "header2" to "2"))
Ähnliches gilt für Cookies:
val response = khttp.get(
url = "http://httpbin.org/get",
cookies = mapOf("cookie1" to "1", "cookie2" to "2"))
Wir können auch auf Header und Cookies zugreifen, die vom Server in der Antwort gesendet werden:
val contentType : String = response.headers["Content-Type"]
val sessionID : String = response.cookies["JSESSIONID"]
7.2. Fehler behandeln
Es gibt zwei Arten von Fehlern, die bei HTTP auftreten können: Fehlerantworten wie 404 - Nicht gefunden, die Teil des Protokolls sind; und Low-Level-Fehler wie "Verbindung abgelehnt".
Die erste Art führt nicht dazu, dass khttp Ausnahmen auslöst. stattdessenwe should check the Response statusCode property:
val response = khttp.get(url = "http://httpbin.org/nothing/to/see/here")
if(response.statusCode == 200) {
process(response)
} else {
handleError(response)
}
Fehler auf niedrigerer Ebene führen stattdessen dazu, dass Ausnahmen vom zugrunde liegenden Java-E / A-Subsystem ausgelöst werden, z. B.ConnectException.
7.3. Streaming-Antworten
Manchmal kann der Server mit einem großen Teil des Inhalts antworten und / oder es kann lange dauern, bis er antwortet. In diesen Fällen möchten wir die Antwort möglicherweise in Blöcken verarbeiten, anstatt darauf zu warten, dass sie abgeschlossen ist und Speicher belegt.
Wenn wir die Bibliothek anweisen möchten, uns eine Streaming-Antwort zu geben, müssen wirtrue alsstream-Argument übergeben:
val response = khttp.get(url = "http://httpbin.org", stream = true)
Dann können wir es in Stücken verarbeiten:
response.contentIterator(chunkSize = 1024).forEach { arr : ByteArray -> handleChunk(arr) }
7.4. Nicht standardmäßige Methoden
In dem unwahrscheinlichen Fall, dass wir eine HTTP-Methode (oder ein HTTP-Verb) verwenden müssen, die khttp nicht nativ bereitstellt - beispielsweise für eine Erweiterung des HTTP-Protokolls wie WebDAV - werden wir weiterhin behandelt.
Tatsächlich werden alle Funktionen im khttp-Paket, die HTTP-Methoden entsprechen, mit einer generischenrequest-Funktion implementiert, die wir auch verwenden können:
khttp.request(
method = "COPY",
url = "http://httpbin.org/get",
headers = mapOf("Destination" to "/copy-of-get"))
7.5. Andere Eigenschaften
Wir haben nicht alle Funktionen von khttp angesprochen. Beispielsweise haben wir keine Zeitüberschreitungen, Weiterleitungen und Verlaufsdaten oder asynchrone Vorgänge besprochen.
The official documentation ist die ultimative Informationsquelle über die Bibliothek und alle ihre Funktionen.
8. Fazit
In diesem Tutorial haben wir gesehen, wie HTTP-Anforderungen in Kotlin mit der idiomatischen Bibliothek khttp gestellt werden.
Die Implementierung all dieser Beispiele finden Sie inthe GitHub project - dies ist ein Maven-Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.