Введение в библиотеку создания веб-приложений RODA

Андрей Васильев

2020

Передача документов в сети Интернет

Базовыми протоколами, на основании которых происходит соединение между браузером и сервером, являются TCP и IP:

  • IP обеспечивает всем уникальные адреса в сети Интернет
  • TCP обеспечивает надёжную передачу данных между конкретными узлами и приложениями в сети Интернет

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

Поверх протокола TCP реализован протокол HTTP, Hyper Text Transport Protocol—базовый протокол для передачи документов

По протоколу HTTP передаются HTML-документы, CSS-документы, JavaScript-документы, JSON-документы и т.д.

Роли в протоколе HTTP

Данный протокол выделяет следующие элементы:

  • Сервер постоянно работает и ожидает подключения
  • Клиенты инициализируют соединение и выполняют запрос к серверу
  • Прокси-серверы прозрачно пропускают соединения от клиента к серверу для кеширования, фильтрации и т.д.

В качестве клиентов могут выступать любые приложения, которые реализуют клиентскую часть протокола HTTP

Процесс выполнения HTTP-запроса

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

Базовые аспекты протокола HTTP

  • Изначально протокол задумывался простым для понимания и доступным для чтения обычным человеком
  • Протокол HTTP поддерживает возможность расширения путём указания произвольного набора заголовков
  • Протокол HTTP не включает средств для сохранения состояния, т.е. запросы от клиента обрабатываются на сервере независимо друг от друга
  • Использование заголовка cookies позволят описывать сессии, которые формируют наборы связных запросов между сервером и клиентом

Изменения в новых версиях протокола

  • HTTP2 и HTTP3 изначально бинарные
  • HTTP3 использует UDP в качестве транспортного протокола
  • Поддерживается несколько логических запросов внутри одного транспортного запроса

Процесс выполнения HTTP-запроса

Рассмотрим шаги, которые выполняет клиент во время запроса к серверу

  1. Клиент открывает TCP-соединение с сервером, которое используется для отправки сообщения, приёма ответа

  2. Клиент посылает HTTP-сообщение, например:

    GET / HTTP/1.1
    Host: developer.mozilla.org
    Accept-Language: ru
  3. Сервер отвечает документом на сообщение:

    HTTP/1.1 200 OK
    Date: Sat, 09 Oct 2010 14:28:02 GMT
    ...
     <!DOCTYPE html...
  4. Клиент закрывает или переиспользует TCP-соединение для другого запроса

Разбор структуры HTTP-запроса

GET / HTTP/1.1
Host: uniyar.ac.ru
Accept-Language: ru
  • Первая строка—запрос
    • GET—метод (тип запроса)
    • /—путь по которому осуществляется запрос
    • HTTP/1.1—версия протокола
  • Затем идёт список заголовков, сначала идёт название, а после двоеточия его значение
  • После заголовков может идти тело запроса, его данные

Типы запросов

  • GET-запрос на получение документа по ссылке
  • POST-запрос на передачу данных по ссылке
  • PUT-запрос на обновление ресурса по ссылке
  • DELETE-запрос на удаление ресурса по ссылке

Разбор HTTP-ответа

Как и в запросе, каждая строка несёт свою смысловую нагрузку

HTTP/1.1 200 OK
Date: Sat, 09 Oct 2010 14:28:02 GMT
...
  • Первая строка — состояние ответа
    • HTTP/1.1—версия протокола, по которому происходит ответ
    • 200—код ответа сервера, указывающий результат обработки
    • OK—краткое и неполное описание кода ответа
  • Список заголовков ответа
  • После заголовка обычно идёт тело ответа, включающее документ

Группы кодов статуса

В протоколе определены следующие группы кодов ответа

  • 100-199 — Информационные ответы
  • 200-299 — Успешные ответы
  • 300-399 — Перенаправления
  • 400-499 — Ошибки в запросе от клиента
  • 500-599 — Ошибки в работе сервера

Часто используемые ответы

  • 200 — запрос был выполнен успешно
  • 301 — перенесён на постоянной основе
  • 302 — документ временно перенесён
  • 404 — документ не найден

Пути к документам в HTTP

Для определения пути к документу используется специальный формат, называемый URI, Universal Resource Identifier:

[схема ":"] путь ["?" запрос] ["#" фрагмент]

схема описывает способ связи

  • file — файл на локальной файловой системе
  • http — доступ по протоколу HTTP

путь к документу, зависит от схемы

  • абсолютный — от корня ресурса
  • относительный — от текущего документа

запрос содержит дополнительные параметры

фрагмент выделяет компонент в документе

Реализация серверного HTTP-стека в Ruby

В основе реализации всего современного серверного HTTP-стека для Ruby приложений лежит библиотека Rack

  • Предлагает единый подход для обработки входящих запросов и формирования ответов на них
  • Описывает стандартные интерфейсы как для веб-серверов, так и для приложений

Без использования Rack каждому веб-серверу потребовалось бы реализовывать поддержку каждой библиотеки для создания веб-приложений

Существует множество веб-серверов: puma, unicorn, thin и т. д., обладающими различными свойствами

На основе библиотеки Rack созданы библиотеки и фреймворки: Ruby on Rails, Sinatra, Hanami, RODA, Cuba

Краткий обзор Rack

Rack больше всего интересен для разработчиков

  • низкоуровневых инструментов (серверов, библиотек)
  • универсальных промежуточных обработчиков: журналирование запросов, фильтрация и т.д.

Реализация Rack-промежуточного слоя

Компонент, совместимый с Rack, должен обладать следующими характеристиками:

  • обрабатывать метод call, которому передаётся 1 аргумент — информация о запросе, включающий путь, заголовки, параметры и т.д.
  • возвращать массив из трёх элементов: статус HTTP, заголовки, тело

Такими компонентами могут выступать лямбда-блоки

Rack::Builder

Класс Rack::Builder предоставляет предметный язык программирования, который позволяет соединять между собой промежуточные слои

Он предоставляет следующие методы:

  • use позволяет подключить промежуточный слой
  • map позволяет привязать обработчики к определённым путям
  • run запускает приложение для обработки запросов

Файл config.ru

Джем rack поставляет приложение rackup, которое предназначено для запуска Rack-приложений. Его конфигурационный файл — config.ru

require_relative 'app'
require_relative 'middleware_logger'

use MiddlewareLogger
run App.new

Библиотека RODA

RODA — это библиотека, облегчающая написание веб-приложений на Ruby

Ключевые особенности:

  • Простая для понимания, сфокусирована на задаче обработке запросов
  • Ключевой элемент — дерево маршрутизации
  • Надёжность за счёт возможности применения неизменяемого состояния, что позволяет легко запускать обработку запросов в несколько потоков
  • Построено на модульной системе, что позволяет выбирать подходящие дополнения для решения конкретной задачи
  • Одна из самых быстрых Rake-библиотек среди всех предлагаемых на Ruby стеке

Архитектура RODA-приложений

Большинство Rack-приложений можно рассматривать как MVC-приложения:

  • Модель — это код, описывающий работу предметной области
  • Вид — это HTML-страницы, возвращаемые веб-сервером при обращении к нему
  • Контроллер — это код по обработке HTTP-запросов, написанный с использованием библиотеки RODA

В такой архитектуре к коду, использующему RODA, предъявляются стандартные требования к контроллеру:

  • Он не должен знать много о предметной области
  • Основная задача — проверка входящих параметров
  • Цикл работы: принять запрос, передать обработанные параметры в модель, передать полученные данные из модели в вид
  • Объём кода — минимальный