Основы обработки HTTP-запросов
#
Васильев Андрей Михайлович, 2024
Версии презентации
Архитектура серверных http4k-приложений
#
- http4k позволяет использовать несколько разных реализаций HTTP-серверов
- Каждую библиотеку можно настроить для оптимального быстродействия
- Логика обработки запросов описывается функциональным типом HttpHandler
- Для улучшения производительности функциональный тип вызывается на нескольких
потоках исполнения
- Библиотека HTTP-сервера тоже работает в многопоточном режиме
Maven-зависимости
#
- http4k состоит из множества компонентов, которые взаимодействуют между собой и
интегрируются с внешними компонентами
- Для реализации сервера необходимо подключить ядро библиотеки и реализацию
сервера:
- Ядро:
"org.http4k:http4k-core:VERSION"
- Сервер Netty:
"org.http4k:http4k-server-netty:VERSION"
Библиотека http4k позволяет использовать множество существующих
серверов:
- Apache
- Jetty
- Ktor
- Netty
- Ratpack
- Undertow
Простейший HTTP-сервер
#
typealias HttpHandler = (Request) -> Response
Функция связывается с сервером с помощью 1 строки кода. Это позволяет отделить
бизнес-логику от реализации сервера:
val app: HttpHandler = // ...
val jettyServer = app.asServer(Netty(9000)).start()
- После запуска данное приложение будет доступно по адресу http://localhost:9000
- Конфигурация сервера описывается с помощью интерфейса
ServerConfig
- Настройки по умолчанию можно попытаться улучшить, если
выполнить объективные замеры производительности
Описание HTTP-обработчика
#
Обработчиком HTTP-запроса является является функциональный тип HttpHandler
Он может быть создан либо с использованием лямбда-выражения:
val handler: HttpHandler = { request: Request -> Response(OK) }
Либо с использованием класса, реализующего данный функциональный тип:
class SomeHandler : HttpHandler {
override fun invoke(request: Request) : Response = Response(OK)
}
val handler = SomeHandler()
- В любом случае входными данными является класс
Request
- Выходными данными является объект класса
Response
Формирование ответа
#
Для описания HTTP-ответа используется класс Response
- Минимально необходимая информация — HTTP-статус ответа, который описывает класс
Status
, предоставляющий множество констант
- Для установки других частей ответа предоставляются соответствующие функции:
body
— установить новое тело, строку для ответа
header
— установить новое значение для конкретного заголовка
headers
— установить новое значение для набора заголовков
Данные методы не изменяют объект, а предоставляют его копию, у которого
установлены новые значения
- Каждый отдельный экземпляр класса
Response
является неизменяемым
- Большинство методов внутри себя вызывают метод
copy
классов данных
Статусы ответов
#
http4k предлагает класс org.http4k.core.Status
, описывающий статус ответа и
предоставляющий константы для описания стандартных статусов
Status.OK
, успешный результат
#
- HTTP-код: 200
- Назначение: запрос был обработан, получен корректный результат
Status.BAD_REQUEST
, некорректный зпрос
#
- HTTP-код: 400
- Назначение: запрос невозможно обработать ввиду наличия в нём проблем
Status.NOT_FOUND
, документ не найден
#
- HTTP код: 404
- Назначение: запрос к несуществующему на сервере документу
Тело ответа
#
Тело ответа передаётся клиенту для дальнейшей обработки. Его можно:
- Сформировать самостоятельно в форме строки или бинарных данных
- Использовать специальные подсистемы http4k для формирования ответа
- Предоставление структурированных документов JSON, XML, GraphQL и т.д.
- Предоставление текстовых HTML-документов
- Предоставление произвольных данных в виде текста
Для установления тела ответа объекты Response предоставляют функцию body
val response = Response(Status.OK).body("Важное сообщение")
Указание типа документа
#
Наибольшее количество запросов клиенты делают ради получения документов
- Получение документа со списком других документов
- Получение документов с детальным описанием элементов
- Получение документов со сводкой по элементам системы
Клиент может
- предполагать какой тип данных вернёт ему сервер
- автоматически определять тип данных
- ориентироваться на стандартный заголовок
Content-Type
Сервер не может своим ответом повлиять на логику обработки ответа на стороне
клиента
Указание типа документа в http4k
#
Наши сервера будут сообщать пользователям тип документа с помощью Content-Type
Значением заголовка Content-Type
является набор из следующих параметров:
- MIME-тип документа, media-type
- кодировка, charset
- директива составных сущностей, boundary
Возможные корректные варианты:
- text/javascript; encoding=utf-8
- text/html; charset=utf-8
- application/json; charset=utf-8
Установка заголовка ответа напрямую
#
HttpMessage, и соответственно Response, предоставляет функцию header
:
fun header(name: String, value: String?): HttpMessage
val response = Response(Status.OK)
.header("Content-Type", "application/json; charset=utf-8")
.body("{\"hello\": \"world\"}")
Использование специальной подсистемы http4k
#
- http4k предоставляет удобный класс
org.http4k.core.ContentType
- И набор констант для описания разных типов содержимого:
APPLICATION_JSON
,
TEXT_HTML
и т.д.
- Данным классом можно воспользоваться с помощью функции-расширения
org.http4k.lens.contentType
val response = Response(Status.OK)
.contentType(ContentType.APPLICATION_JSON)
.body("{\"hello\": \"world\"}")