Жизненный цикл запроса в Hapi

Жизненный цикл запроса в Hapi определяется строгой последовательностью этапов, через которые проходит каждое входящее HTTP-событие. Архитектура фреймворка построена так, чтобы обеспечить предсказуемую обработку, расширяемость и контроль на каждом уровне выполнения запроса.

На самом первом этапе запрос попадает в HTTP-сервер Hapi, где создаётся объект запроса. В этот момент формируются базовые структуры данных:

  • метод HTTP (GET, POST, PUT и т.д.)
  • URL и его параметры
  • заголовки
  • тело запроса (если присутствует)
  • контекст соединения

Hapi не передаёт запрос сразу в обработчики маршрутов. Сначала он проходит через систему внутренних хуков и плагинов, которые могут модифицировать поведение обработки.

Валидация соединения и предварительная обработка

Перед маршрутизацией выполняется проверка базовой корректности соединения. На этом этапе могут быть задействованы:

  • обработка TLS/HTTPS контекста
  • проверка лимитов соединений
  • базовые плагины безопасности

Далее запрос поступает в систему предварительных обработчиков. В Hapi они реализуются через lifecycle extensions:

  • onRequest
  • onPreAuth
  • onPostAuth
  • onPreHandler

Эти этапы позволяют вмешиваться в обработку до того, как запрос попадёт в бизнес-логику.

onRequest: первое перехватывание запроса

Фаза onRequest является самой ранней точкой вмешательства. Здесь запрос можно:

  • модифицировать (например, переписать URL)
  • заблокировать до дальнейшей обработки
  • перенаправить на другой маршрут

Этот этап выполняется до маршрутизации, поэтому маршруты ещё не сопоставлены.

Маршрутизация запроса

После onRequest система маршрутизации определяет, какой handler должен обработать запрос. Hapi использует внутренний роутинг, основанный на методе и пути.

В процессе маршрутизации происходит:

  • сопоставление URL с зарегистрированными маршрутами
  • выбор подходящего handler’а
  • определение параметров маршрута (params)
  • подготовка контекста выполнения

Если маршрут не найден, запрос переходит в обработку ошибки 404.

onPreAuth: подготовка к аутентификации

После выбора маршрута начинается этап подготовки к аутентификации. На уровне onPreAuth можно:

  • изменить credentials
  • подменить стратегию аутентификации
  • выполнить дополнительные проверки до авторизации

Этот этап критичен для систем, где требуется динамическое управление доступом.

Аутентификация

Hapi имеет встроенную систему стратегий аутентификации. На этом этапе происходит:

  • выбор стратегии (например, cookie, JWT, basic auth)
  • извлечение credentials из запроса
  • проверка валидности токена или сессии
  • формирование объекта request.auth

Если аутентификация не проходит, выполнение прерывается и возвращается ошибка 401 или 403.

onPostAuth: пост-аутентификационная логика

После успешной аутентификации запускается onPostAuth. Здесь уже доступны данные пользователя, и можно:

  • накладывать дополнительные ограничения доступа
  • логировать факт входа
  • модифицировать поведение запроса в зависимости от роли пользователя

Этот этап часто используется для реализации RBAC и ABAC моделей.

Валидация входных данных

Перед попаданием в основной обработчик происходит проверка входящих данных. В Hapi для этого используется схема валидации (обычно через Joi).

Проверяются:

  • параметры URL (params)
  • query-параметры (query)
  • тело запроса (payload)
  • заголовки (headers)

Если данные не соответствуют схеме, выполнение прерывается с ошибкой 400.

onPreHandler: финальная подготовка

На этапе onPreHandler запрос уже полностью сформирован, а данные валидированы. Здесь выполняются:

  • подготовка контекста бизнес-логики
  • подключение дополнительных сервисов
  • трансформации данных перед handler’ом

Этот этап считается последним рубежом перед основной логикой обработки.

Handler: выполнение бизнес-логики

Основной обработчик маршрута — это место, где реализуется бизнес-логика. Здесь:

  • выполняются запросы к базе данных
  • обрабатываются вычисления
  • формируется ответ

Handler может быть синхронным или асинхронным. Возвращаемое значение автоматически интерпретируется Hapi как payload ответа.

onPreResponse: обработка ответа

После выполнения handler’а запрос переходит в фазу формирования ответа. На этапе onPreResponse можно:

  • изменить response перед отправкой
  • обернуть данные в стандартный формат
  • обработать ошибки централизованно

Этот этап часто используется для унификации API-ответов.

Формирование HTTP-ответа

После завершения всех lifecycle-этапов Hapi формирует финальный HTTP-ответ:

  • устанавливаются заголовки
  • код состояния (status code)
  • сериализация payload
  • обработка cookies

Если response был модифицирован в onPreResponse, именно его версия отправляется клиенту.

Отправка ответа клиенту

Финальный этап — передача ответа по сети. После этого соединение может быть:

  • закрыто (HTTP/1.0 или без keep-alive)
  • оставлено открытым для повторных запросов

На этом жизненный цикл запроса считается завершённым.

Обработка ошибок на любом этапе

В любой точке жизненного цикла может возникнуть ошибка. Hapi централизует её обработку через:

  • встроенный механизм Boom-ошибок
  • onPreResponse для перехвата исключений
  • error handlers на уровне сервера

Ошибки преобразуются в стандартизированные HTTP-ответы с корректными статус-кодами.

Приоритет и порядок выполнения расширений

Все lifecycle hooks выполняются строго последовательно. Порядок нельзя нарушить:

  1. onRequest
  2. маршрутизация
  3. onPreAuth
  4. аутентификация
  5. onPostAuth
  6. валидация
  7. onPreHandler
  8. handler
  9. onPreResponse
  10. отправка ответа

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

Влияние плагинов на жизненный цикл

Hapi построен вокруг системы плагинов, которые могут:

  • добавлять собственные lifecycle hooks
  • изменять поведение маршрутов
  • внедрять middleware-подобную логику

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

Поток данных через request object

На протяжении всего жизненного цикла объект request постепенно обогащается:

  • raw данные HTTP
  • параметры маршрута
  • результат аутентификации
  • валидированные данные
  • результат handler’а

Это делает его центральным контейнером состояния запроса.

Контекст выполнения и изоляция

Каждый запрос в Hapi выполняется в собственном контексте. Это означает:

  • отсутствие глобального состояния между запросами
  • изоляция данных пользователей
  • безопасная параллельная обработка

Такой подход критичен для масштабируемых серверных приложений.

Завершение обработки и освобождение ресурсов

После отправки ответа Hapi:

  • освобождает память, связанную с request
  • завершает асинхронные операции (если они не “висят”)
  • закрывает контекст выполнения

Это позволяет эффективно обрабатывать большое количество параллельных запросов без утечек памяти.