HTTP-приложения #
Васильев Андрей Михайлович, 2024
Версии презентации
Интернет гипертекста #
В рамках концепции гипертекста доступ ко всем данным может быть осуществлён с помощью одного приложения, браузера, способного отображать документы и удобным образом переходить к другим документам в сети
- Веб-браузер является средством просмотра HTML-документов
- HTML-документы содержат текст и ссылки на другие документы
- Документы передаются с сервера на клиент с помощью протокола HTTP
- Для доступа к данным пользователю достаточно знать доменное имя сервера
Базовые технологии интернета гипертекста
- Протокол обмена документами HTTP был утверждён в 1992 году
- Язык разметки документов HTML был утверждён в 1993 году
Протокол HTTP #
Является протоколом прикладного уровня, решающий задачу передачи документов по общей сети удобным для пользователя образом
История создания #
- Версия 0.9 представлена в 1990-1992 годах
- Версия 1.0 стандартизирована в 1996 году
- Версия 1.1 стандартизирована в 1999 году
- Версия 2 стандартизирована в 2015 году
- Версия 3 стандартизирована в 2022 году
Новые версии обратно совместимы со старыми, добавляют новые возможности
Связанные сетевые технологии #
- Стек сетевых протоколов TCP / IP (1980-е)
- Транспортный протокол TCP
- Используется в протоколах HTTP 1.1 (1999), HTTP 2 (2015)
- Транспортный протокол UDP
- Используется в протоколе HTTP 3 (2022)
- Транспортный протокол TCP
- Безопасность транспортного уровня TLS (1999, 1.3 — 2018)
- Является основой для защищённого варианта HTTP, HTTPS
- Система доменных имён DNS (1983, 1987)
- Доменные имена поверх HTTPS, DoH (2018)
Данные технологии детально не рассматриваются в курсе, но их знание является необходимым для разработки больших продуктовых систем
Архитектура HTTP #
В рамках протокола выделяются 2 роли: сервер и клиент
- Приложение-сервер работает постоянно и ожидает подключения от клиента
- Клиент подключается к серверу и передаёт запрос на получение документа
- Сервер возвращает запрошенный документ, если он существует
- Сервер закрывает соединение после передачи документа
Особенности HTTP-приложений #
- HTTP-сервер работает постоянно, так как он не знает когда к нему планирует обратиться клиент
- HTTP-сервер может одновременно обрабатывать запросы от множества клиентов
- Клиент может послать очередной запрос с любой задержкой: 10мс, 2000мс и т.д.
- В последних версиях протокола HTTP сервер может инициировать отправку данных на сторону клиента
HTTP-приложения являются распределёнными приложениями, в которых как сервер, так и клиент должен поддерживать совместное актуальное состояние
Роли участников в HTTP-взаимодействии #
Между клиентом и сервером может находится несколько проксирующих серверов
- Задача прокси-серверов, находящихся рядом с клиентом состоит в уменьшении объёма запрашиваемых данных (в кешировании):
- запросы могут быть одинаковыми у разных клиентов
- один клиент может инициировать запросы к одному ресурсу
- В современны браузерах встроен агрессивный кеширующий сервер
- Задачи прокси-сервера, находящегося рядом с серверами, состоит в балансировке нагрузки между серверами
- По географическому положению клиента
- По степени нагруженности серверов
- В зависимости от клиента
HTTP-запросы #
Изначально HTTP-протокол разрабатывался как текстовый, то есть клиент и сервер обмениваются специально оформленными текстовыми сообщениями друг с другом
В новых версиях текст был заменён на бинарное представление для ускорения передачи данных, но концептуально логика взаимодействия не изменилась
- Клиент открывает TCP-соединение с сервером, которое используется для отправки сообщения, и приёма ответа
- Клиент посылает HTTP-сообщение, например:
GET /index.html HTTP/1.1 Host: developer.mozilla.org Accept-Language: ru
- Сервер отвечает документом на сообщение:
HTTP/1.1 200 OK Date: Sat, 09 Oct 2010 14:28:02 GMT ... <!DOCTYPE html...
- Клиент закрывает или переиспользует TCP-соединение для другого запроса
Разбор структуры HTTP-запроса #
GET /index.html HTTP/1.1
Host: uniyar.ac.ru
Accept-Language: ru
- Первая строка содержит описание запроса
GET
— метод (тип запроса)/index.html
— путь к документу, к которому осуществляется запросHTTP/1.1
— версия протокола
- На следующих строках указываются заголовки запроса в формате
название : значение
- После заголовков может идти тело запроса, данные для передачи
Разбор структуры HTTP-ответа #
HTTP/1.1 200 OK
Date: Sat, 09 Oct 2010 14:28:02 GMT
...
Content-Length: 2761
Content-type: text-html; charset=utf-8
<!DOCTYPE html...
- Первая строка описывает результаты запроса
HTTP/1.1
— версия протокола200
— код ответа сервера, указывающий результат обработкиOK
— краткое текстовое описание кода ответа
- Список заголовков ответа
- Если в рамках ответа возвращается документ, то среди заголовков точно будет указан
Content-Length
, содержащий размер документа в символах - Через пустую строку после заголовков идёт тело документа
Группы кодов статуса #
В протоколе определены следующие группы кодов ответа
100-199
— Информационные ответы200-299
— Успешные ответы300-399
— Перенаправления400-499
— Ошибки в запросе от клиента500-599
— Ошибки в работе сервера
Часто используемые ответы #
200
— запрос был выполнен успешно301
— перенесён на постоянной основе302
— документ временно перенесён404
— документ не найден
Базовый шаблон взаимодействия #
В качестве клиента в HTTP-взаимодействии может выступать любое приложение, которое реализует HTTP-протокол
Зачастую таким клиентом выступает веб-браузер, который получает и отображает веб-страницу для пользователя
- Пользователь указывает в браузере адрес документа, который хочет просмотреть
- Браузер выполняет запрос к серверу и получает в ответ HTML-документ
- Документ внутри себя указывает другие документы, которые нужны для отображения и работы HTML-документа:
- Изображения и видео-файлы для отображения на странице
- CSS-документы определяющие внешний вид элементов на странице
- JavaScript-документы для выполнения интерактивных действий
- WebAssembly-модули для выполнения вычислений
- Браузер запрашивает все эти элементы и формирует из них интерактивный документ, с которым может взаимодействовать пользователь
Особенности протокола HTTP #
Протокол HTTP является простым #
- Протокол изначально текстовый и состоит из небольшого набора элементов
- С помощью доступных инструментов анализирутся бинарные запросы HTTP 2 и 3
Протокол HTTP является расширяемым #
Благодаря механизму заголовков можно добавлять новую семантику к запросам и ответам. Достаточно ввести соглашение между клиентом и сервером
В версии HTTP/1.1 ввели заголовок keep-alive
, который говорит серверу, что клиент может в рамках одного TCP-соединения можно выполнить несколько HTTP-запросов
Формируется новый протокол поверх HTTP
Есть более 100 стандартных заголовков запросов и ответов
В HTTP каждый запрос индивидуален #
С точки зрения протокола HTTP каждый запрос отдельный запрос не зависит от других
- На уровне протокола нельзя сослаться на предыдущий или следующий запрос
- Внутри запроса можно передавать данные, которые связывают запросы друг с другом, но логика по их обработки выходит за пределы HTTP-протокола
Клиент должен передать всю необходимую информацию при каждом запросе
HTTP поддерживает сессии #
Благодаря заголовку Cookies
сервер и браузер могут реализовать механизм сессий:
- Клиент и сервер могут устанавливать новые значения
- Клиент и сервер обязуются их передавать вместе с запросами и ответами
- Данные внутри должны быть небольшого объёма
Раздача статического контента #
Задачей первых HTTP-серверов стояла раздача файлов с файловой системы
Таким образом для идентификации документов в качестве основы были взяты пути к файлам на жёстком диске в рамках ОС UNIX
- Все данные хранятся в едином дереве каталогов
- Разделителем пути является
/
Пример пути к файлу: /var/www/site/index.html
Внешнему наблюдателю не надо показывать все файлы, а только файлы в определённом каталоге, например в /var/www/site
Идентификация документов #
Для указания местоположения целевого документа в сети Интернет используется Uniform Resource Identifier, URI
- Представляет собой символьную строку, которая идентифицирует ресурс
- Может быть применена как в сети Интернет, так и в других средах
Структура URI #
[ схема ":" ] [ // источник ] путь [ "?" запрос ] [ "#" фрагмент ]
Блоки внутри [ ]
являются опциональными и могут быть опущены
- Схема обычно описывает протокол доступа:
http
,ftp
,file
и т.д. - Источник содержит адрес сервера, на котором расположен документ
- Путь описывает местоположение документа на источнике
- Запрос описывает дополнительные параметры к получаемому документу
- Фрагмент содержит указание на часть документа
Идентификация в рамках протокола HTTP #
Рассмотрим веб-сервер web-app.net
, раздающий документы из файловой системы
Структура ФС:
/var/www/site
├── 404.html
├── assets
│ └── main.css.map
├── feed.xml
├── index.html
├── labs
│ ├── 001-lab-01.html
│ └── 002-lab-02.html
├── labs.html
├── reference
│ ├── books.html
│ ├── editors.html
│ ├── schedule.html
│ └── tasks.html
└── topics.html
- Схема доступа к данным —
http
- Иерархическая часть строится из имени сервера и расположения документа на сервере
- Корневым каталогом для сервера является
/var/www/site
Для файла /var/www/site/index.html
URI будет
http://web-app.net/index.html
Для файла /var/www/site/reference/tasks.html
http://web-app.net/reference/tasks.html
В рамках протокола HTTP иерархия соответствует файловой системе с разделителем /
Идентификация файлов на файловой системе #
Для указания пути к локальным файлам существует собственная схема — file
file://host/path
- Префикс схемы
file://
- Затем идёт указание имени компьютера, на котором расположен файл
- Если имя компьютера не указано, то считается текущий компьютер
localhost
- Иерархическая часть описывает местоположение файла в рамках файловой системы
- В качестве разделителя используется прямой слеш
/
- Для файла в ОС семейства Windows
- Путь:
C:\my-site\information.html
- URI с хостом:
file://localhost/C:/my-site/information.html
- URI:
file:///C:/my-site/information.html
- Путь:
- Для файла в Unix-подобных ОС
- Путь:
/var/www/my-site/index.html
- URI с хостом:
file://localhost/var/ww/my-site/index.html
- URI:
file:///var/www/my-site/index.html
- Путь:
Полные и частичные URI #
Ключевая особенность гипертекста — формировать ссылки между документами в сети, связывая их в единую сеть
- Ссылка может вести на документ на другом сервере (обязательно полный URI)
- Ссылка может вести на документ на текущем сервере
В рамках последней схемы удобно использовать частичные URI
Частичный URI #
- При формировании частичного URI не надо указывать ни схему, ни название сервера, на котором находится документ, только путь
- Частичные URI могут быть использованы только внутри документа для описания пути к другим документам, пользователям браузер показывает обычно полные URI
- Клиент (браузер) при обращении по частичной ссылке преобразует её в абсолютную
URI документа = абсолютный URI текущего документа + частичный URI
Частичные URI могут быть относительными или абсолютными
Относительные и абсолютные частичные URI #
- Абсолютный частичный путь — из корня сайта
- Относительный частичный путь — путь относительно текущего документа
Отличить абсолютный путь от относительного легко — он начинается с символа /
/
├── css
│ └── style.css
├── index.html
└── topic
├── list.html
├── topic-1.html
└── topic-2.html
- Абсолютный частичный путь к документу
index.html
:/index.html
- Абсолютный частичный путь к документу
style.css
:/css/style.css
Они будут одинаковыми для любого просматриваемого документа на сайте
При формировании относительных частичных путей используется каталог, в котором находится документ с ссылкой
- Для файла
index.html
таким каталогом каталогом является/
- Для файла
topic-2.html
—/topic
Абсолютные частичные URI на документы #
При формировании ссылки к документу внутри одного сайта удобно использовать абсолютный путь
Рассмотрим структуру сайта example-app.net
/
├── css
│ └── style.css
├── index.html
└── topic
├── list.html
├── topic-1.html
└── topic-2.html
В рамках сайта у каждого файла будет свой собственный абсолютные частичные URL:
style.css
:/style.css
index.html
:/index.html
list.html
:/topic/list.html
topic-1.html
:/topic/topic-1.html
topic-2.html
:/topic/topic-2.html
Пример построения относительных путей #
Построим относительный путь от файла /index.html
/
├── css
│ └── style.css
├── index.html
└── topic
├── list.html
├── topic-1.html
└── topic-2.html
- Пользователь обращается к стартовой странице
http://example-app.net/index.html
- Для оформления содержимого в документе указана ссылка на CSS-стили:
css/style.css
- Клиентское приложение формирует абсолютный путь
- Высчитывается расположение документа,
/
- К пути добавляется относительный путь
css/style.css
:/css/style.css
- Формируется URL, в котором добавляется схема, и имя сервера
http://example-app.net
:http://example-app.net/css/style.css
- Высчитывается расположение документа,
Относительный путь к родительскому каталогу #
Рассмотрим построение пути от файла topic-1.html
к файлу /css/style.css
/
├── css
│ └── style.css
├── index.html
└── topic
├── list.html
├── topic-1.html
└── topic-2.html
Для обращения к родительскому каталогу следует использовать специальное название каталога — ..
Этот специальный каталог присутствует и в обычной файловой системе и может быть использован не только в
- Пользователь обращается к стартовой странице
http://example-app.net/topic/topic-1.html
- Для оформления содержимого в документе указана ссылка на CSS-стили:
../css/style.css
- Клиентское приложение формирует абсолютный путь
- Высчитывается расположение документа на сервере,
/topic/
- К пути добавляется относительный путь
../css/style.css
:/topic/../css/style.css
/css/style.css
- Формируется URL, в котором добавляется схема, и имя сервера
http://example-app.net
:http://example-app.net/css/style.css
- Высчитывается расположение документа на сервере,
Какие URI использовать? #
Выделили следующие типы URI:
- Полный URI, включающий схему и имя хоста и путь к файлу
- Абсолютный частичный URI, включающий путь к файлу от корня
- Относительный частичный URI, включающий путь от расположения файла
При ссылке на документ на другом сайте #
Возможно использовать только полный URI
Ссылка на документ собственного сайта #
Удобно использовать частичный URI, так как:
- Он значительно короче полного пути, его легче использовать
- Адрес сайта может измениться за время его существования
Абсолютный или относительный частичный URI? #
К плюсам использования относительного частичного URI относят:
- Возможность работы с документами как через веб-сервер (схема
http
), так и через уровень файловой системы (схемаfile
) - Возможность размещения документов сайта не только в корне сервера
- Возможность предоставления одинаковых документов в разных частях нескольких сайтов (может быть и недостатком)
- Возможность предоставления документов другим пользователям
Ограничения относительных частичных URI:
- Некоторые документы требуют указания абсолютных частичных URI
- Для формирования относительных URI может потребоваться больше усилий
Обзор библиотеки http4k #
http4k — это набор инструментов для создания серверных и клиентских HTTP-приложений
- Предоставляет функциональный интерфейс для решения задач
- Не реализует самостоятельно функции сервера и клиента, а использует промышленные технологии для реализации нужных функций
- Включает средства для решения следующих задач:
- Обработка HTTP-запросов
- Взаимодействие с помощью WebSocket
- Запуск с собственным сервером, без сервера, встраивается в Jakarta
- Реализация контрактов OpenApi 3 (Swagger)
- Работа со множеством шаблонизаторов
- Поддержка работы со множеством типов данных: JSON, XML, YAML
- Поддержка всех видов тестирования веб-приложений
Ключевые концепции http4k #
- Основано на базовых концепциях функциональных языков программирования
- Вся логика по обработке HTTP-запросов описывается одной функцией
- Не используются техники метапрограммирования для решения задач
- Минимальный объём зависимостей
- Поддержка разработки приложения через написание тестов без сложной инфраструктуры
- Быстрый запуск и остановка приложений
- Предоставляет средства строгой типизации для обработки HTTP-сообщений
- Поддержка контрактов: генерация документации OpenApi, логичное поведение «по умолчанию»
Ключевые типы http4k #
Библиотека http4k предоставляет набор функциональных типов, которые позволяют создавать, тестировать и разворачивать HTTP-приложения
HttpMessage #
Данная структура является неизменяемой и описывает запросы и ответы
- Неизменяемые структуры позволяют избегать множества ошибок
- Цепочка формирования структур позволяет отследить изменения в приложении
- Позволяет удобно тестировать логику работы приложения
Детали интерфейса HttpMessage #
Класс содержит следующие свойства
version
— версия протокола HTTPheaders
— список HTTP-заголовковbody
— тело сообщения
Класс предоставляет методы для установки
- Значения конкретного свойства
- Значений отдельных заголовков
Запросы и ответы #
Для представления этих элементов внутри приложения используются интерфейсы Request и Response, которые унаследованы от интерфейса HttpMessage
interface Request : HttpMessage #
Помимо полей интерфейса HttpMessage предоставляет следующие поля
method
— HTTP-метод запроса (GET, PUT, …)source
— сетевая информация об источнике запросаuri
— адрес документа в запросе
interface Response : HttpMessage #
Помимо полей интерфейса HttpMessage предоставляет следующие поля
status
— статус HTTP-ответа
Тип HttpHandler #
typealias HttpHandler = (Request) -> Response
Данный функциональный тип моделирует работу входящих и исходящих HTTP-запросов
- Сервер должен предоставить реализацию данного функционального интерфейса, т.е. реализовать логику по обработке запроса и формирования ответа
- Клиент должен выполнить сетевой запрос к удалённому серверу и получить ответ на поставленный запрос
Использование клиента #
Библиотека http4k предоставляет обвязку поверх множества существующих клиентов:
val client: HttpHandler = ApacheClient()
Запуск сервера #
Функция может быть связана с сервером с помощью 1 строки кода. Это позволяет отделить бизнес-логику от реализации сервера:
val app: HttpHandler = // ...
val jettyServer = app.asServer(Netty(9000)).start()
Библиотека http4k позволяет использовать множество существующих серверов:
- Apache
- Jetty
- Ktor
- Netty
- Ratpack
- Undertow
Создание проекта с помощью генератора #
Проект создать можно с помощью:
- С помощью генератора проектов https://toolbox.http4k.org/project
- Инструмента командного интерфейса http4k
- Создать проект вручную или с помощью генератора проектов от Gradle
Шаги по созданию проекта с помощью генератора #
- Project core
- Kind of app writing: Server
- Server-side WebSocket: No
- Server engine: Netty
- HTTP client library: OkHttp
- Functional modules
- JSON serialization library: Jackson
- Templating library: Pebble
- Functional modules: Multipart form
- Functional modules, inetgrations: None
- Testing: Kotest
- Application identity
- Main class name: WebApplication
- Base package name: ru.uniyar
- Build tooling:
- Build tool: Gradle
- Packaging type: zip
Важные особенности проекта Gradle #
Файл gradle.properties
содержит версии библиотек и используемых инструментов
junitVersion=5.10.0
http4kVersion=5.8.1.0
kotlinVersion=1.9.10
Файл build.gradle
описывает параметры сборки и запуска приложения
apply plugin: "application"
mainClassName = "su.yarsu.WebApplicationKt"
dependencies {
implementation("org.http4k:http4k-client-okhttp:${http4kVersion}")
implementation("org.http4k:http4k-core:${http4kVersion}")
implementation("org.http4k:http4k-multipart:${http4kVersion}")
implementation("org.http4k:http4k-format-jackson:${http4kVersion}")
implementation("org.http4k:http4k-server-netty:${http4kVersion}")
implementation("org.http4k:http4k-template-pebble:${http4kVersion}")
}
Запуск приложения из шаблона #
При прохождении мастера по созданию приложения была использована система сборки Gradle, которая будет использована при проверке лабораторных работ
С её помощью приложение можно легко запустить, выполнив команду в командном интерфейсе:
./gradlew run
После выполнения всех необходимых действий по скачиванию зависимостей и сборке приложения, оно будет запущено и веб-сервер будет доступен по http://localhost:9000
Создание 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
не изменяют объект, но предоставляют его копию, у которого установлены новые значения. В результате каждый отдельный экземпляр класса Response
является неизменяемым, но очень легко сформировать объект с нужным состоянием
Статусы ответов #
OK
, успешный результат
#
- HTTP код: 200
- Назначение: устанавливается когда по запросу был найден документ
NOT_FOUND
, документ не найден
#
- HTTP код: 404
- Назначение: устанавливается, когда по запросу не был найден документ
- Ответ приложения на библиотеке http4k по умолчанию
FOUND
, перенаправление
#
- HTTP код: 302
- Назначение: перенаправить к адресу документа после создания новой сущности
Тело ответа #
Тело ответа передаётся клиенту для дальнейшей обработки. Его можно:
- Сформировать строку вручную
- Использовать специальные подсистемы для формирования ответа
- Предоставление структурированных документов JSON, XML, GraphQL и т.д.
- Предоставление текстовых HTML-документов
- Предоставление произвольных данных в виде текста
Для установления тела ответа объекты Response предоставляют метод body
:
val response = Response(OK).body("Важное сообщение")
Данные для формирования ответа #
Зачастую информации из запроса недостаточно для формирования ответа:
- Необходимо получить доступ к данным из базы данных
- Необходимо выполнить проверку уровня доступа пользователя
- Необходимо обратиться к ресурсам
Для решения этих задач в конструктор обработчика надо передать зависимости:
// Конструктор в виде класса
class UserListerHandler(private val users: List<String>): HttpHandler {
override fun invoke(request: Request): Response =
Response(OK).body(users.joinToString(", "))
}
val userHandler = UserListerhandler(listOf("Иван", "Марья"))
// Констуктор в виде функции-генератора
fun messageResponder(message:String): HttpHandler = {
Response(OK).body(message)
}
val messageHandler = messageResponder("Привет!")
Инфиксные функции в Kotlin #
Функция может быть помечена ключевым словом infix
, если
- Функция является членом другой функции или расширением
- Функция принимает только один параметр
- Параметр не описывает произвольное количество агументов
- Параметр не должен иметь значения по умолчанию
Описание инфиксной функции и её использование
infix fun Int.shl(x: Int): Int { /*...*/ }
1 shl 2
1.shl(2)
Обязательно указывать как получателя, так и параметр
Описание маршрутизатора #
Основная задача сервера — обработка запросов от клиента. В рамках HTTP-протокола клиент формирует запрос к серверу и указывает к документу
При разработке сервера необходимо определить связь между маршрутом и обработчиком
Функция routes
позволяет описать данную связь:
val handlerOne: HttpHandler = { Response(OK).body("First response") }
val handlerTwo: HttpHandler = { Response(OK).body("Second response") }
val app = routes (
"first" bind GET to handlerOne,
"second".bind(GET).to(handlerTwo),
)
handler1
иhandler2
являются обработчиками, HttpHandler- Конфигурация обрабатывает пути
/first
и/second
- Данный обработчик вернёт ответ с кодом 404, если для указанного пути нет обработчика
Описание связи маршрута и обработчика #
routes(
"bob" bind GET to { Response(OK).body("you GET bob") },
"rita" bind POST to { Response(OK).body("you POST rita") },
"sue" bind DELETE to { Response(OK).body("you DELETE sue") },
)
- Описание маршрута с помощью шаблонной строки
- Вызов инфиксной функции
bind
связывает строку с методом по его обработке, возвращая объект типаPathMethod
- Указание названия HTTP-метода, который надо обработать
- Инфиксная функция
PathMethod.to
связывает результат работы предыдущего метода с обработчиками запроса, порождая объект типа RoutingHttpHandler - Передача обработчика HttpHandler в качестве обработчика маршрута
Сформированный список объектов RoutingHttpHandler передаётся на вход функции routes
, которая сама возвращает обработчик RoutingHttpHandler
Поддерживаемые HTTP-методы #
http4k поддерживает следующие HTTP-методы: GET
, POST
, PUT
, DELETE
, OPTIONS
, TRACE
, PATCH
, PURGE
, HEAD
. Методы описаны в перечислении org.http4k.core.Method
Вложенные маршруты #
Функции routes
в качестве аргумента можно передать объект RoutingHttpHandler, созданный в результаты другого вызова функции routes
:
val webCourseRouter = routes(
"topic" bind GET to { Response(OK).body("Веб-разработка") },
"length" bind GET to { Response(OK).body("1 семестр") }
)
val unixCourseRouter = routes(
"topic" bind GET to { Response(OK).body("Использование UNIX") },
"length" bind GET to { Response(OK).body("1 или 2 семсетра")},
)
val coursesApp = routes(
"test/ping" bind GET to { Response(OK).body("pong") },
"unix" bind unixCourseRouter,
"web" bind webCourseRouter,
)
Обрабатываются маршруты:
/test/ping
/unix/topic
,/unix/length
/web/topic
,/web/length
Динамические маршруты #
В рамках строки-шаблона могут содержаться переменные, которые можно использовать в рамках обработки запроса
routes (
"/book/{title}" bind GET to { request ->
Response.invoke(Status.OK).body(request.path("title").orEmpty())
},
"/author/{name}/latest" bind GET to { request ->
Response.invoke(Status.OK).body(request.path("name").orEmpty())
},
)
- Шаблоны могут располагаться в любой части строки, их может быть несколько
- Для получения переданных данных из пути используется метод
Request.path
fun Request.path(name: String): String?
- Метод
String?.orEmpty()
возвращает пустую строку, если ссылка содержитnull
Раздача статических данных #
Для отображения HTML-документов необходимо предоставить пользователю возможность получить CSS и JavaScript-документы. Для этого используется функция static
Предположим, что базовым пакетом приложения является org.example
, а в рамках ресурсов в пакете org.example.public
находятся статические данные, то для их показа используем метод Classpath
класса ResourceLoader
routes(
static(ResourceLoader.Classpath("/org/example/public")),
)
Если данные находятся на жёстком диске, то необходимо использовать загрузчик с жёсткого диска, метод Directory
routes(
static(ResourceLoader.Directory("../uploads")
)
Архитектурный взгляд на приложение #
Под архитектурой подразумевается вопрос грамотного разделения приложения на компоненты, каждый из которых решает чётко поставленную задачу. Т.е. так, чтобы из небольших компонентов составлять полнофункциональное сложное приложение
Компоненты приложения:
- Маршрутизатор HTTP-запросов
- Обработчики HTTP-запросов
- Реализация классов предметной области
- Шаблонизаторы
Все компоненты соединяются между собой внутри маршрутизатора