HTTP-запросы с Kotlin и KHTTP

HTTP-запросы с Kotlin и KHTTP

1. Вступление

Протокол HTTP и API-интерфейсы, построенные на нем, сегодня играют центральную роль в программировании.

На JVM у нас есть несколько доступных опций, от низкоуровневых до очень высокоуровневых библиотек, от устоявшихся проектов до новых детей в блоке. Тем не менее, большинство из них ориентированы в первую очередь на Java-программы.

В этой статьеwe’re going to look at khttp, an idiomatic Kotlin library for consuming HTTP-based resources и API.

2. зависимости

Чтобы использовать библиотеку в нашем проекте, сначала мы должны добавить ее в наши зависимости:


    khttp
    khttp
    0.1.0

Поскольку это еще не сделано в Maven Central, мы также должны включить репозиторий JCenter:


    central
    http://jcenter.bintray.com

Версия 0.1.0 является текущей на момент написания. Мы, конечно, можемcheck JCenter for a newer one.

3. Основное использование

Основы протокола HTTP просты, хотя мелкие детали могут быть довольно сложными. Следовательно, у khttp простой интерфейс.

For every HTTP method, we can find a package-level function in the khttp package, напримерget,post и так далее.

Все функции принимают один и тот же набор аргументов и возвращают объектResponse; мы увидим подробности этого в следующих разделах.

В этой статье мы будем использовать полную форму, например,khttp.put. В наших проектах мы можем, конечно, импортировать и, возможно, переименовать эти методы:

import khttp.delete as httpDelete

Note: we’ve added type declarations for clarity throughout code examples, потому что без IDE за ними будет сложно следить.

4. Простая просьба

Every HTTP request has at least two required components: a method and a URL. В khttp метод определяется вызываемой функцией, как мы видели в предыдущем разделе.

URL-адрес является единственным обязательным аргументом для метода; Итак, мы можем легко выполнить простой запрос:

khttp.get("http://httpbin.org/get")

В следующих разделах мы будем считать все запросы успешно выполненными.

4.1. Добавление параметров

Нам часто приходится предоставлять параметры запроса в дополнение к базовому URL, особенно для запросов GET.

khttp’s methods accept a params argument, который представляет собойMap пар "ключ-значение" для включения в запросString:

khttp.get(
  url = "http://httpbin.org/get",
  params = mapOf("key1" to "value1", "keyn" to "valuen"))

Обратите внимание, что мы использовали функциюmapOf для созданияMap на лету; результирующий URL-адрес запроса будет:

http://httpbin.org/get?key1=value1&keyn=valuen

5. Тело запроса

Другая распространенная операция, которую нам часто приходится выполнять, - это отправка данных, обычно в виде полезных данных запроса POST или PUT.

Для этого библиотека предлагает несколько вариантов, которые мы рассмотрим в следующих разделах.

5.1. Отправка полезной нагрузки JSON

We can use the json argument to send a JSON object or array. Может быть нескольких типов:

  • JSONObject илиJSONArray, предоставленные библиотекой org.json

  • AMap, который преобразуется в объект JSON

  • Collection,Iterable или массив, который преобразуется в массив JSON

Мы можем легко превратить наш предыдущий пример GET в POST, который отправит простой объект JSON:

khttp.post(
  url = "http://httpbin.org/post",
  json = mapOf("key1" to "value1", "keyn" to "valuen"))

Обратите внимание, что преобразование из коллекций в объекты JSON невелико. Например,List изMap не будет преобразован в массив JSON объектов JSON, а скорее в массив строк.

Для глубокого преобразования нам потребуется более сложная библиотека сопоставления JSON, например Jackson. Средство преобразования библиотеки предназначено только для простых случаев.

5.2. Отправка данных формы (URL-адрес закодирован)

Для отправки данных формы (в кодировке URL, как в HTML-формах) мы используем аргументdata сMap:

khttp.post(
  url = "http://httpbin.org/post",
  data = mapOf("key1" to "value1", "keyn" to "valuen"))

5.3. Загрузка файлов (составная форма)

Мы можем отправить один или несколько файлов, закодированных как запрос данных из нескольких частей.

В этом случае мы используем аргументfiles:

khttp.post(
  url = "http://httpbin.org/post",
  files = listOf(
    FileLike("file1", "content1"),
    FileLike("file2", File("kitty.jpg"))))

Мы видим, что khttp использует абстракциюFileLike, которая представляет собой объект с именем и содержанием. Содержимое может быть строкой, байтовым массивом,File илиPath.

5.4. Отправка необработанного содержимого

Если ни один из вышеперечисленных вариантов не подходит, мы можем использоватьInputStream для отправки необработанных данных в качестве тела HTTP-запроса:

khttp.post(url = "http://httpbin.org/post", data = someInputStream)

В этом случае нам, скорее всего, придется вручную установить и некоторые заголовки, о чем мы поговорим в следующем разделе.

6. Обработка ответа

До сих пор мы видели различные способы отправки данных на сервер. Но многие операции HTTP полезны из-за данных, которые они также возвращают.

khttp основан на блокировке ввода-вывода, поэтомуall functions corresponding to HTTP methods return a Response object содержит ответ, полученный от сервера.

Этот объект имеет различные свойства, к которым мы можем получить доступ, в зависимости от типа содержимого.

6.1. Ответы JSON

Если мы знаем, что ответом является объект или массив JSON, мы можем использовать свойстваjsonObject иjsonArray:

val response : Response = khttp.get("http://httpbin.org/get")
val obj : JSONObject = response.jsonObject
print(obj["someProperty"])

6.2. Текстовые или двоичные ответы

Если мы хотим вместо этого читать ответ какString, мы можем использовать свойствоtext:

val message : String = response.text

Или, если мы хотим прочитать это как двоичные данные (например, загрузка файла) используем свойствоcontent:

val imageData : ByteArray = response.content

Наконец, мы также можем получить доступ к базовомуInputStream:

val inputStream : InputStream = response.raw

7. Расширенное использование

Давайте также рассмотрим пару более сложных шаблонов использования, которые в целом полезны и которые мы еще не рассматривали в предыдущих разделах.

7.1. Обработка заголовков и файлов cookie

All khttp functions take a headers argument, который представляет собойMap имен и значений заголовков.

val response = khttp.get(
  url = "http://httpbin.org/get",
  headers = mapOf("header1" to "1", "header2" to "2"))

Аналогично для печенья:

val response = khttp.get(
  url = "http://httpbin.org/get",
  cookies = mapOf("cookie1" to "1", "cookie2" to "2"))

Мы также можем получить доступ к заголовкам и файлам cookie, отправленным сервером в ответе:

val contentType : String = response.headers["Content-Type"]
val sessionID : String = response.cookies["JSESSIONID"]

7.2. Обработка ошибок

В HTTP могут возникать два типа ошибок: ответы об ошибках, такие как 404 - Not Found, которые являются частью протокола; и ошибки низкого уровня, такие как «отказано в соединении».

Первый тип не приводит к исключениям, генерирующим khttp; вместо этогоwe 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)
}

Вместо этого ошибки более низкого уровня приводят к возникновению исключений из базовой подсистемы ввода-вывода Java, такой какConnectException.

7.3. Потоковые ответы

Иногда сервер может ответить большим фрагментом контента и / или долго отвечать. В этих случаях мы можем захотеть обработать ответ кусками, а не ждать его завершения и занять память.

Если мы хотим, чтобы библиотека давала нам потоковый ответ, мы должны передатьtrue в качестве аргументаstream:

val response = khttp.get(url = "http://httpbin.org", stream = true)

Затем мы можем обработать его кусками:

response.contentIterator(chunkSize = 1024).forEach { arr : ByteArray -> handleChunk(arr) }

7.4. Нестандартные методы

В том маловероятном случае, когда нам понадобится использовать HTTP-метод (или глагол), который khttp не поддерживает изначально - скажем, для некоторого расширения протокола HTTP, такого как WebDAV, - мы все еще покрыты.

Фактически, все функции в пакете khttp, которые соответствуют HTTP-методам, реализованы с использованием общей функцииrequest, которую мы тоже можем использовать:

khttp.request(
  method = "COPY",
  url = "http://httpbin.org/get",
  headers = mapOf("Destination" to "/copy-of-get"))

7.5. Другие преимущества

Мы не затронули все возможности khttp. Например, мы не обсуждали тайм-ауты, перенаправления, историю или асинхронные операции.

The official documentation - это основной источник информации о библиотеке и всех ее функциях.

8. Заключение

В этом руководстве мы увидели, как выполнять HTTP-запросы в Kotlin с идиоматической библиотекой khttp.

Реализацию всех этих примеров можно найти вthe GitHub project - это проект Maven, поэтому его должно быть легко импортировать и запускать как есть.