Опубликовано: :: Теги: ,

Это заключительная статья из серии, посвящённой пониманию веб-разработки. В серии три статьи, в которых разбиралось следующее:

  1. Устройство клиент-серверного взаимодействия;
  2. Изучение того, как браузер получает и отображает данные;
  3. → Развернём собственный локальный сервер, чтобы убедиться, что сервер — это просто программа.

Что такое веб-сервер

Веб-сервер — это программа, которая принимает запросы от браузера или другого клиента и отвечает на них. Основная задача — доставить файлы: HTML, CSS, JSON и т.д.

Существует два основных типа серверов:

СтатическийДинамический
Отдаёт файлы «как есть». Подходит для простых сайтов, документации, интерфейсов одностраничных приложений (SPA).Обрабатывает данные, взаимодействует с базой данных, может создавать или изменять ресурсы, что дает возможность работать с API.

В этой статье для примера используется статический сервер, который по умолчанию поставляется при установке Python. Он не обрабатывает логику, но показывает, как контент становится доступен через HTTP.

Подробнее:

Перед началом работы

Для повторения примеров понадобятся установленные в системе Python и Git, а также терминал по выбору. Примеры подготовлены на компьютере с macOS; для Windows предлагаются отдельные команды. В качестве терминала на Windows я настоятельно рекомендую использовать Git Bash, который устанавливается вместе с Git.

Я привожу в качестве примера консольные команды, но при желании можно делать практически то же самое с помощью альтернативных средств и клиентов.

Навигация в терминале

Для работы в терминале полезно будет помнить, как устроена навигация по файловой системе. Работа с сервером часто происходит в UNIX-подобном окружении, так что стоит научиться использовать следующие команды:

  • pwd — покажет, где вы сейчас находитесь (полный путь);
  • ls — покажет содержимое текущей директории;
  • cd имя_директории — перейти в директорию (cd — сокращение от change directory);
  • cd .. — подняться на уровень выше;
  • cd ~ — вернуться в домашнюю директорию.

Пример:

  1. Вы в /home/user/desktop/.
  2. Хотите перейти в /home/user/desktop/web-server-tutorial.
  3. Введите: cd web-server-tutorial.
  4. Чтобы вернуться обратно, введите: cd ...

Проверка наличия Python

Убедитесь, что у вас установлен Python 3. Откройте терминал (Git Bash, iterm2 или другой в зависимости от ОС) и введите команду:

python3 --version

или

python --version

Если вы видите версию вроде Python 3.9 или выше — всё готово.

Если команда не найдена, скачайте Python с официального сайта.

Клонирование подготовленного проекта

Я подготовил проект и разместил его на GitHub. Он содержит минимальную структуру, необходимую для демонстрации работы с данными, используя локальный сервер.

Перейдите в то место, куда вы хотите склонировать репозиторий, и выполните:

git clone https://github.com/AlexJameson/web-server-tutorial.git

Перейдите в директорию:

cd web-server-tutorial

Проект содержит следующие файлы:

  • index.html — главная страница с кнопкой для загрузки данных. По нажатию кнопки вызывается код на JavaScript, запрашивающий и отображающий данные.
  • 404.html — страница, которая показывается при ошибке.
  • api/posts/ — список из 10 постов.

Такая структура имитирует реальное API, где:

  • /api/posts/1.json — возвращает содержимое первого поста.
  • /api/posts/2.json — второго и так далее.

Вы можете открыть любой файл в текстовом редакторе (рекомендую VS Code), чтобы увидеть, как устроены данные. Как можно заметить, в этом проекте нет ни одного файла, относящегося к Python. Локальный сервер этого и не требует. В самой простой реализации он просто делает директорию доступной по сети или локально.

Ключевая идея этой статьи состоит как раз в том, что с определённой точки зрения любой сервер — это просто программа. Она позволяет обращаться к ресурсам по определённым адресам. Можно заметить, что ресурсы при запросах доступны по тем путям, по которым они действительно находятся в директории.

Запуск сервера

Модуль HTTPServer из стандартной библиотеки не требует ничего, кроме установленного в системе Python. Этот модуль реализует простой HTTP-сервер на сокетах. Он слушает указанный порт, принимает входящие TCP-соединения, обрабатывает HTTP-запросы и отдаёт файлы из директории, в которой он запущен.

  1. Находясь в директории web-server-tutorial, выполните в терминале:

    python3 -m http.server 8000
    
  2. Сервер запущен. Вы увидите сообщение:

    Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

    или

    Serving HTTP on :: port 8000 (http://[::]:8000/) ...

Что такое порт

Порт — это точка соединения с определённым номером, через которую данные передаются по сети. Порты бывают физические и программные. В этой статье я имею в виду программные порты. Операционные системы по умолчанию используют разные порты для разных протоколов: порт 80 для HTTP, 22 для SSH, 443 для HTTPS и т.д. Для локальных тестов в этой статье используем точно не занятый порт 8000.

Вы можете выбрать любой другой свободный порт, например:

python -m http.server 8080

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

Подробнее:

Проверка в браузере

  1. Откройте браузер и перейдите по следующему адресу:

    http://localhost:8000

  2. Вы увидите главную страницу с кнопкой Загрузить пост #1.

  3. Нажмите на неё и посмотрите на пост, который загружает локальный сервер. Это такой же контент, который мы получали при обращении к сервису JSONPlaceholder в одной из предыдущих статей.

Можно проанализировать этот запрос:

  1. Откройте DevTools (F12) и перейдите на вкладку Network.

  2. Обновите страницу и нажмите кнопку снова. Вы увидите использованный метод, статус запроса, объём переданных ресурсов и время загрузки.

devtools view

Подробнее:

Что такое localhost

В примерах выше можно увидеть, что адрес локального сервера может быть http://0.0.0.0:8000 или http://[::]:8000/, а в браузере вообще отображается http://localhost:8000. На самом деле, это практически один и тот же адрес, но в разных представлениях.

localhost — это имя, которое всегда указывает на ваш компьютер (хост) и полностью соответствует адресу 127.0.0.1 при подключении к локальному серверу по IPv4 (или ::1 через IPv6, который стараются использовать многие современные системы). Такой адрес называют loopback-адресом и он служит только для приёма соединений с той же машины, где работает сервер.

0.0.0.0 — специальный зарезервированный IPv4-адрес, который используется на серверах для прослушивания всех сетевых интерфейсов (например Wi-Fi, Ethernet и т.д.). А [::] — его аналог для IPv6. Такие адреса не маршрутизируются: маршрутизатор не знает, куда отправить пакет с адресом назначения 0.0.0.0.

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

Подробнее:

Проверка через curl

Клиентом может быть не только браузер. Попробуем отправить запросы к серверу с помощью curl.

  1. Откройте ещё один терминал или вкладку, чтобы не прерывать работу сервера в первом терминале.

  2. Проверьте, что сервер доступен:

    curl -I http://localhost:8000
    

    Вы должны увидеть:

    HTTP/1.0 200 OK
    Server: SimpleHTTP/0.6 Python/3.9.16
    Content-Type: text/html
    
  3. Теперь проверьте доступ к данным:

    curl http://localhost:8000/api/posts/1.json
    

    Вы увидите то же содержимое поста, которое до этого появилось по нажатию кнопки в интерфейсе.

    Помимо поста номер 1, можно также заменить номер и получить содержимое других постов.

    А ещё вы можете разместить любые другие файлы в директории, перезапустить сервер и пройти по соответствующим путям.

  4. А что будет, если запросить несуществующую страницу, например:

    curl -I http://localhost:8000/xyz
    

    Сервер покажет содержимое файла 404.html.

  5. Теперь попробуйте открыть эту или любую другую не существующую страницу в браузере. Вы увидите контент страницы, который был задан в файле 404.html.

Кстати, в браузере можно также посмотреть содержимое файлов в директории /api/posts/. Попробуйте открыть эти посты и посмотреть, как браузер отображает JSON и что показывается при этом в DevTools.

Остановка сервера

Чтобы остановить сервер:

  1. Вернитесь в терминал, где он запущен, и нажмите Ctrl + C. Это сочетание типично для прерывания процессов в UNIX-средах.

  2. Попробуйте обновить страницу в браузере — соединение будет отклонено.

Чем отличается сервер c API от использованного примера

Сервер, который использовался в этом сценарии, довольно сильно отличается даже от простых серверов, использующихся для реальных задач. HTTP-сервер в Python используется для простейшего тестирования. Также его возможности куда скромнее, чем у настоящих статических серверов вроде Nginx, которые позволяют решать задачи разного уровня сложности.

По многим причинам он не подходит для продакшена. Например, в HTTPServer реализуются только базовые проверки безопасности — нельзя установить шифрованное соединение, нет аутентификации и много другого.

Сервера с API обычно реализуют куда более сложную логику. Они обрабатывают запросы разных видов, а иногда вместо запросов ожидают вызовы, как в случае с gRPC. Они обрабатывают и сохраняют данные, взаимодействуя с СУБД и делают много других вещей.

Подробнее:

Заключение

В этой серии статей я постарался осветить основные составляющие веб-разработки как предметной области. Основная задача заключалась в том, чтобы дать возможность своими руками сделать вещи. Они раз за разом повторяются в той или иной форме при работе с веб-сервисами и приложениями.

Самое важное — базовые принципы не меняются в зависимости от технологий. Протоколы могут быть разными, реализации могут отличаться друг от друга, но суть останется неизменной — на любой request должен быть response.