Курс языка программирования Raku / Функциональное, конкурентное, реактивное и веб-программирование / Веб-программирование / Простой HTTP-сервер

Обслуживание множества запросов

Сервер с предыдущей страницы обработал один запрос и остановился. Настоящий сервер продолжает работать, отвечая клиенту за клиентом. Заверните шаги «принять — прочитать — ответить» в loop — и, поскольку цикл разделяет переменные, объявленные вокруг него, между запросами можно сохранять состояние. Здесь сервер считает своих посетителей и сообщает каждому его номер:

my $listener = IO::Socket::INET.new(
    :listen,
    :localhost('127.0.0.1'),
    :localport(8080),
);

my $customer = 0;

loop {
    my $conn = $listener.accept;
    $conn.recv;
    $customer++;

    # heredoc с qq:to даёт опрятный шаблон — переменная интерполируется прямо в нём
    my $body = qq:to/END/;
        Hello!
        You are customer number $customer.
        Thanks for visiting.
        END

    # сначала отправляем заголовок, затем тело — двумя отдельными записями
    $conn.print("HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n");
    $conn.print($body);

    $conn.close;
}

.accept блокирует выполнение, пока клиент не подключится, и затем возвращает новый сокет для этого разговора. Поскольку $customer живёт вне цикла, она переживает переход от запроса к запросу: первый посетитель — покупатель 1, второй — 2 и так далее. Цикл сам по себе никогда не кончается, поэтому сервер работает, пока вы не остановите его по Ctrl-C.

Стоит обратить внимание на две детали:

  • Ответ пишется в две части. Первый .print отправляет HTTP-заголовок — строку состояния, тип содержимого и пустую строку, завершающую заголовки. Второй отправляет тело. HTTP безразлично, придёт это одной записью или несколькими, поэтому разделение позволяет держать неизменную протокольную обвязку отдельно от того, что действительно меняется.

  • Тело берётся из шаблона. qq:to/END/ — это heredoc, строка qq, которая тянется до строки END. Она занимает несколько строк и интерполирует $customer так же, как любая строка в двойных кавычках, что делает её изящным средством шаблонизации для сборки ответа. (Это одна из конструкций кавычек, встречавшихся раньше в курсе.)

Подключитесь несколько раз, чтобы посмотреть, как растёт счётчик:

$ curl http://127.0.0.1:8080/
Hello!
You are customer number 1.
Thanks for visiting.
$ curl http://127.0.0.1:8080/
Hello!
You are customer number 2.
Thanks for visiting.

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

Навигация по курсу

Ответ на запрос   |   Путь в верхнем регистре


💪 Или перейдите сразу к упражнению этого раздела.