HTTP-запрос — это сообщение, которое клиент (браузер, мобильное приложение, утилита curl) отправляет серверу по протоколу HTTP, чтобы получить ресурс или передать данные. В паре с ним идет HTTP-ответ — сообщение, которым сервер отвечает клиенту. Это разные сообщения с похожей структурой, и путать их не стоит: запрос задает намерение (метод + адрес), ответ сообщает результат (код состояния + данные).
Содержание
- Как работает HTTP: клиент и сервер
- Структура HTTP-сообщения
- Стартовая строка запроса
- Методы: GET, POST, PUT, PATCH, DELETE
- Коды состояния: группы 1xx-5xx
- Пример реального запроса и ответа
- Как отправить запрос из Python
- HTTPS: тот же HTTP, но по шифрованному каналу
- HTTP/1.1, HTTP/2 и HTTP/3: коротко о различиях
- Выводы
- Где применяется / связь с практикой
- FAQ
Ниже разберем по порядку: из чего состоят запрос и ответ, чем отличаются методы GET, POST, PUT, PATCH и DELETE, что означают коды 1xx-5xx, зачем нужен HTTPS и чем различаются HTTP/1.1, HTTP/2 и HTTP/3. Материал рассчитан на новичков, которые уже видели браузер и командную строку.
Как работает HTTP: клиент и сервер
HTTP — это протокол прикладного уровня для обмена данными в вебе (расшифровка — HyperText Transfer Protocol, «протокол передачи гипертекста»). Работает он по модели «запрос — ответ»: клиент шлет запрос, сервер его обрабатывает и возвращает ответ. Одно соединение может нести много таких пар.
По умолчанию обычный HTTP использует TCP-порт 80, а защищенный HTTPS — порт 443. Порт можно задать явно в адресе (например, :8080), тогда клиент обратится именно к нему.
Важно развести два соседних понятия. Сам HTTP отвечает за формат сообщений и семантику методов и кодов. Доставку байтов по сети обеспечивает нижележащий транспорт — TCP (в HTTP/1.1 и HTTP/2) или QUIC поверх UDP (в HTTP/3). Ниже видно, что версия HTTP — это в основном про то, как сообщение упаковано и передано, а не про смысл GET или кода 404.
Структура HTTP-сообщения
Запрос и ответ устроены по одной схеме из четырех частей:
- Стартовая строка — одна строка. У запроса она задает метод, цель и версию; у ответа — версию, код состояния и его пояснение.
- Заголовки (headers) — строки вида
Имя: Значение, по одной на строку. Уточняют запрос или ответ: тип содержимого, длину, кодировку, авторизацию. - Пустая строка — отделяет заголовки от тела и сообщает, что метаданные закончились.
- Тело (body) — опциональные данные: у запроса это, например, отправляемая форма или JSON, у ответа — HTML-страница, картинка или JSON.
Имена заголовков нечувствительны к регистру, но по соглашению каждое слово пишут с заглавной буквы (Content-Type, User-Agent).
Стартовая строка запроса
Стартовая строка запроса состоит из трех частей: метод, цель (обычно путь к ресурсу) и версия протокола. Например:
GET /journal/ HTTP/1.1
Здесь метод — GET, цель — путь /journal/, версия — HTTP/1.1. Домен в этой строке не пишут: его несет обязательный заголовок Host. Цель может включать строку запроса (query string) — параметры после ?, разделенные &: GET /search?q=http&page=2 HTTP/1.1.
Методы: GET, POST, PUT, PATCH, DELETE
Метод говорит, что сделать с ресурсом по указанному адресу. Помимо перечисленных есть HEAD (как GET, но сервер возвращает только заголовки без тела) и OPTIONS (какие методы допустимы для ресурса).
У методов есть два свойства, которые часто смешивают, но они про разное:
- Безопасный (safe) — запрос не меняет состояние на сервере (только чтение).
- Идемпотентный (idempotent) — повтор того же запроса оставляет состояние сервера таким же, как после одного запроса. Любой безопасный метод идемпотентен, но не наоборот.
| Метод | Что делает | Безопасный | Идемпотентный |
|---|---|---|---|
| GET | запрашивает ресурс | да | да |
| HEAD | как GET, но только заголовки | да | да |
| OPTIONS | сообщает допустимые методы | да | да |
| POST | отправляет данные, создает/запускает обработку | нет | нет |
| PUT | помещает ресурс целиком по адресу | нет | да |
| PATCH | частично изменяет ресурс | нет | обычно нет |
| DELETE | удаляет ресурс | нет | да |
PUT идемпотентен, потому что кладет ресурс в заданное состояние: сколько раз ни повтори тот же PUT, на сервере будет один и тот же результат. POST не идемпотентен — два одинаковых POST на создание заказа обычно создадут два заказа.
DELETE идемпотентен по итоговому состоянию: первый запрос удаляет ресурс, второй уже ничего не меняет (ресурса нет). Код при этом может отличаться — первый вернет 200 или 204, второй нередко 404, но состояние сервера одинаково. PATCH идемпотентен не всегда: он зависит от вида правки (например, «увеличить счетчик на 1» повтор изменит).
Коды состояния: группы 1xx-5xx
Стартовая строка ответа несет код состояния (status code) — трехзначное число, по которому клиент понимает исход. Коды делятся на пять групп по первой цифре:
| Группа | Смысл | Частые примеры |
|---|---|---|
| 1xx | информационные, промежуточные | 100 Continue, 101 Switching Protocols |
| 2xx | успех | 200 OK, 201 Created, 204 No Content |
| 3xx | перенаправление | 301 Moved Permanently, 302 Found, 304 Not Modified |
| 4xx | ошибка на стороне клиента | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 429 Too Many Requests |
| 5xx | ошибка на стороне сервера | 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable |
Пара соседних кодов, которые путают: 401 — «не аутентифицирован» (сервер не знает, кто ты, нужен вход), а 403 — «аутентифицирован, но доступ запрещен». И 301 (перенаправление навсегда, поисковики переносят вес на новый URL) против 302 (временно, старый URL остается основным).
Тело в ответе есть не всегда: 204 No Content и 304 Not Modified его не несут по определению — вся нужная информация в заголовках и самом коде.
Пример реального запроса и ответа
Так выглядит типичный обмен по HTTP/1.1 (это упрощенный пример; точный набор заголовков и их значения зависят от клиента, сервера и момента). Запрос:
GET /journal/ HTTP/1.1
Host: otus.ru
User-Agent: curl/8.4.0
Accept: */*
Пустая строка в конце обязательна — она завершает заголовки. Тела у такого GET нет. Ответ:
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 18 Sep 2026 09:00:00 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 51234
<!doctype html>
<html>...
Стартовая строка ответа HTTP/1.1 200 OK сообщает версию, код 200 и пояснение OK. Дальше идут заголовки, пустая строка и тело — HTML-страница.
Как отправить запрос из Python
Ниже — вариант через популярную библиотеку requests. Она не входит в стандартную библиотеку Python, поэтому в изолированной среде или песочнице модуля может не быть — тогда сначала pip install requests. Пример также требует доступа в сеть, поэтому вывод зависит от текущего ответа сервера.
# pip install requests (в стандартную библиотеку не входит; нужен доступ в сеть)
import requests
resp = requests.get("https://otus.ru/journal/", timeout=10)
print(resp.status_code) # 200 при успешном ответе
print(resp.request.method) # GET
print(resp.headers["Content-Type"]) # напр.: text/html; charset=UTF-8
# Точные значения зависят от сети и текущего ответа сервера
Если ставить пакеты нельзя, тот же GET делает модуль urllib из стандартной библиотеки (доступ в сеть по-прежнему нужен):
# Только стандартная библиотека - без установки пакетов (нужен доступ в сеть)
from urllib.request import Request, urlopen
req = Request("https://otus.ru/journal/", method="GET")
with urlopen(req, timeout=10) as resp:
print(resp.status) # 200
print(resp.headers["Server"]) # напр.: nginx
Для POST с телом (requests) данные обычно кладут в JSON, а метод и заголовки библиотека проставит сама:
import requests
resp = requests.post(
"https://httpbin.org/post",
json={"login": "user", "id": 42},
timeout=10,
)
print(resp.status_code) # 200
print(resp.json()["json"]) # {'login': 'user', 'id': 42}
# httpbin возвращает присланное тело обратно; вывод зависит от доступности сервиса
HTTPS: тот же HTTP, но по шифрованному каналу
HTTPS — это тот же HTTP, но поверх защищенного соединения TLS (порт 443). TLS решает три задачи: шифрует содержимое (стартовую строку, заголовки и тело), проверяет подлинность сервера по его сертификату и защищает данные от изменения в пути. Без него запросы идут открытым текстом, и их можно прочитать или подменить.
Здесь важна граница упрощения. HTTPS скрывает путь, заголовки и тело, но не прячет полностью сам факт соединения: IP-адрес сервера виден, а имя домена обычно видно на этапе установки TLS (поле SNI). И «замок» в браузере означает лишь шифрование канала до сервера, а не то, что сайт добросовестный, — фишинговый сайт тоже может работать по HTTPS.
HTTP/1.1, HTTP/2 и HTTP/3: коротко о различиях
Смысл методов и кодов от версии не меняется — меняется то, как сообщение упаковано и доставлено. Кратко:
| Версия | Год | Транспорт | Что нового |
|---|---|---|---|
| HTTP/1.1 | 1997 | TCP, текстовый формат | постоянные соединения, но запросы в соединении идут по очереди |
| HTTP/2 | 2015 | TCP, бинарные фреймы | мультиплексирование потоков в одном соединении, сжатие заголовков (HPACK) |
| HTTP/3 | 2022 | QUIC поверх UDP | убирает блокировку очереди на транспорте, быстрее устанавливает соединение (QPACK) |
Главная проблема HTTP/1.1 — блокировка очереди (head-of-line): медленный ответ задерживает следующие в том же соединении. HTTP/2 решил это на уровне HTTP, введя параллельные потоки, но осталась блокировка на уровне TCP: потеря одного пакета тормозит все потоки. HTTP/3 переносит транспорт на QUIC (UDP), где потоки независимы, поэтому потеря пакета в одном потоке не блокирует другие.
Выводы
- HTTP-запрос и HTTP-ответ — разные сообщения одной структуры: стартовая строка, заголовки, пустая строка и опциональное тело.
- Метод задает намерение; свойства «безопасный» и «идемпотентный» — про разное: GET/HEAD/OPTIONS безопасны, идемпотентны также PUT и DELETE, а POST и PATCH в общем случае нет.
- Код состояния читается по группам: 2xx — успех, 3xx — перенаправление, 4xx — ошибка клиента, 5xx — ошибка сервера; 401 и 403, 301 и 302 — разные по смыслу.
- HTTPS шифрует и заверяет канал (TLS, порт 443), но «замок» не гарантирует добросовестности сайта.
- Версии HTTP/1.1, HTTP/2 и HTTP/3 меняют упаковку и транспорт, а не смысл методов и кодов; HTTP/3 работает поверх QUIC (UDP).
Где применяется / связь с практикой
Понимание HTTP — базовый навык не только для веб-разработчика, но и для того, кто настраивает и диагностирует сети: за кодами 502/504, редиректами и таймаутами часто стоят прокси, балансировщики и правила фаервола, а не сам код приложения. Читать заголовки, различать 4xx и 5xx и понимать, где TCP, а где QUIC, — это ежедневная работа при разборе инцидентов.
Освойте тему на практике
Системно эти темы (протоколы, TCP/IP, HTTP, TLS, диагностика трафика) разбирают на курсе Сетевой инженер. Если хочется сначала посмотреть формат и уровень без обязательств, загляните на открытые уроки Otus — там разбирают отдельные темы вживую.
Смежные темы: HTTP-сервер на Java: серверные основы на примере своего чата.
FAQ
Чем GET отличается от POST при отправке данных? GET передает параметры в строке запроса внутри URL — они видны в адресе, логах и истории, а длина ограничена; такой запрос удобно кэшировать и повторять. POST кладет данные в тело, они не видны в URL, подходят для больших и приватных данных и для операций, которые меняют состояние.
DELETE идемпотентен, но второй запрос вернул 404 — это ошибка? Нет. Идемпотентность — про итоговое состояние сервера, а не про код: после первого DELETE ресурса уже нет, второй запрос ничего не меняет и корректно отвечает 404. Состояние одинаково, отличается лишь код ответа.
Если у сайта HTTPS и «замок», ему можно доверять? HTTPS гарантирует только шифрование канала и подлинность сертификата для этого домена, но не добросовестность владельца. Мошеннический сайт тоже может получить сертификат и показывать «замок», поэтому проверять стоит само доменное имя, а не только наличие шифрования.



