Это заключительная статья из серии, посвящённой пониманию веб-разработки. В серии три статьи, в которых разбиралось следующее:
- Устройство клиент-серверного взаимодействия;
- Изучение того, как браузер получает и отображает данные;
- → Развернём собственный локальный сервер, чтобы убедиться, что сервер — это просто программа.
Что такое веб-сервер
Веб-сервер — это программа, которая принимает запросы от браузера или другого клиента и отвечает на них. Основная задача — доставить файлы: HTML, CSS, JSON и т.д.
Существует два основных типа серверов:
| Статический | Динамический |
|---|---|
| Отдаёт файлы «как есть». Подходит для простых сайтов, документации, интерфейсов одностраничных приложений (SPA). | Обрабатывает данные, взаимодействует с базой данных, может создавать или изменять ресурсы, что дает возможность работать с API. |
В этой статье для примера используется статический сервер, который по умолчанию поставляется при установке Python. Он не обрабатывает логику, но показывает, как контент становится доступен через HTTP.
Подробнее:
Перед началом работы
Для повторения примеров понадобятся установленные в системе Python и Git, а также терминал по выбору. Примеры подготовлены на компьютере с macOS; для Windows предлагаются отдельные команды. В качестве терминала на Windows я настоятельно рекомендую использовать Git Bash, который устанавливается вместе с Git.
Я привожу в качестве примера консольные команды, но при желании можно делать практически то же самое с помощью альтернативных средств и клиентов.
Навигация в терминале
Для работы в терминале полезно будет помнить, как устроена навигация по файловой системе. Работа с сервером часто происходит в UNIX-подобном окружении, так что стоит научиться использовать следующие команды:
pwd— покажет, где вы сейчас находитесь (полный путь);ls— покажет содержимое текущей директории;cd имя_директории— перейти в директорию (cd— сокращение от change directory);cd ..— подняться на уровень выше;cd ~— вернуться в домашнюю директорию.
Пример:
- Вы в
/home/user/desktop/. - Хотите перейти в
/home/user/desktop/web-server-tutorial. - Введите:
cd web-server-tutorial. - Чтобы вернуться обратно, введите:
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-запросы и отдаёт файлы из директории, в которой он запущен.
Находясь в директории
web-server-tutorial, выполните в терминале:python3 -m http.server 8000Сервер запущен. Вы увидите сообщение:
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.
Нажмите на неё и посмотрите на пост, который загружает локальный сервер. Это такой же контент, который мы получали при обращении к сервису JSONPlaceholder в одной из предыдущих статей.
Можно проанализировать этот запрос:
Откройте DevTools (F12) и перейдите на вкладку Network.
Обновите страницу и нажмите кнопку снова. Вы увидите использованный метод, статус запроса, объём переданных ресурсов и время загрузки.

Подробнее:
Что такое 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.
Откройте ещё один терминал или вкладку, чтобы не прерывать работу сервера в первом терминале.
Проверьте, что сервер доступен:
curl -I http://localhost:8000Вы должны увидеть:
HTTP/1.0 200 OK Server: SimpleHTTP/0.6 Python/3.9.16 Content-Type: text/htmlТеперь проверьте доступ к данным:
curl http://localhost:8000/api/posts/1.jsonВы увидите то же содержимое поста, которое до этого появилось по нажатию кнопки в интерфейсе.
Помимо поста номер 1, можно также заменить номер и получить содержимое других постов.
А ещё вы можете разместить любые другие файлы в директории, перезапустить сервер и пройти по соответствующим путям.
А что будет, если запросить несуществующую страницу, например:
curl -I http://localhost:8000/xyzСервер покажет содержимое файла
404.html.Теперь попробуйте открыть эту или любую другую не существующую страницу в браузере. Вы увидите контент страницы, который был задан в файле
404.html.
Кстати, в браузере можно также посмотреть содержимое файлов в директории /api/posts/. Попробуйте открыть эти посты и посмотреть, как браузер отображает JSON и что показывается при этом в DevTools.
Остановка сервера
Чтобы остановить сервер:
Вернитесь в терминал, где он запущен, и нажмите
Ctrl + C. Это сочетание типично для прерывания процессов в UNIX-средах.Попробуйте обновить страницу в браузере — соединение будет отклонено.
Чем отличается сервер c API от использованного примера
Сервер, который использовался в этом сценарии, довольно сильно отличается даже от простых серверов, использующихся для реальных задач. HTTP-сервер в Python используется для простейшего тестирования. Также его возможности куда скромнее, чем у настоящих статических серверов вроде Nginx, которые позволяют решать задачи разного уровня сложности.
По многим причинам он не подходит для продакшена. Например, в HTTPServer реализуются только базовые проверки безопасности — нельзя установить шифрованное соединение, нет аутентификации и много другого.
Сервера с API обычно реализуют куда более сложную логику. Они обрабатывают запросы разных видов, а иногда вместо запросов ожидают вызовы, как в случае с gRPC. Они обрабатывают и сохраняют данные, взаимодействуя с СУБД и делают много других вещей.
Подробнее:
Заключение
В этой серии статей я постарался осветить основные составляющие веб-разработки как предметной области. Основная задача заключалась в том, чтобы дать возможность своими руками сделать вещи. Они раз за разом повторяются в той или иной форме при работе с веб-сервисами и приложениями.
Самое важное — базовые принципы не меняются в зависимости от технологий. Протоколы могут быть разными, реализации могут отличаться друг от друга, но суть останется неизменной — на любой request должен быть response.