Курс 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.

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

Навігація курсом

Відповідь на запит   |   Шлях у верхньому регістрі


💪 Або перейдіть одразу до вправи цього розділу.