// Engineering Log

HTTP, HTTPS и TLS: Часть 1 — Что такое HTTP: запрос, ответ, методы и коды состояния

Опубликовано 25.09.2026

// Быстрый маршрут

Эта статья относится к теме Сети и маршрутизация.

HTTP (HyperText Transfer Protocol) — протокол прикладного уровня, по которому браузер, мобильное приложение или скрипт запрашивает у сервера ресурс и получает ответ. Ресурсом может быть HTML-страница, картинка, JSON из API или файл для скачивания. HTTP не хранит состояние между запросами: каждый запрос сервер обрабатывает отдельно, а «память» о пользователе — сессию, корзину, вход в личный кабинет — обеспечивают cookie и токены, которые клиент передаёт в заголовках.

Сейчас HTTP описан набором документов IETF 2022 года: RFC 9110 задаёт общую семантику (методы, коды, заголовки), а RFC 9112, 9113 и 9114 — способ передачи по сети для HTTP/1.1, HTTP/2 и HTTP/3. Семантика у всех версий одна, различается только то, как байты идут по проводу. Поэтому всё, что написано в этой части, верно для любой версии.

Как выглядит обмен

Клиент открывает TCP-соединение с сервером (для HTTP — порт 80, для HTTPS — 443), отправляет запрос и ждёт ответ. В HTTP/1.1 это обычный текст, его удобно разглядывать через curl -v:

bash
curl -v http://example.com/

Строки с > — то, что отправил curl, с < — ответ сервера:

> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/8.7.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/html
< Content-Length: 1256
< Cache-Control: max-age=3600
<
<!doctype html>
...

Из чего состоит запрос

  1. Стартовая строка: метод, путь и версия протокола — GET /catalog?page=2 HTTP/1.1. Путь включает строку запроса (?page=2), но не включает фрагмент (#section) — фрагмент браузер на сервер не отправляет.
  2. Заголовки: пары Имя: значение, по одной на строку. Обязателен только Host — по нему сервер понимает, какой из сайтов на этом IP-адресе нужен клиенту.
  3. Пустая строка — конец заголовков.
  4. Тело — необязательно. Его передают методы, которые отправляют данные: POST, PUT, PATCH. Длину тела сервер узнаёт из заголовка Content-Length или из разбивки на части Transfer-Encoding: chunked.

Регистр в именах заголовков не важен: Content-Type и content-type — один заголовок. В HTTP/2 и HTTP/3 имена всегда передаются строчными буквами.

Из чего состоит ответ

  1. Строка состояния: версия, код и поясняющая фраза — HTTP/1.1 404 Not Found. Фраза нужна только человеку, программы смотрят на код; в HTTP/2 и HTTP/3 её нет вовсе.
  2. Заголовки ответа: тип содержимого, длина, правила кеширования, cookie, заголовки безопасности.
  3. Пустая строка и тело.

Методы

Метод говорит серверу, что клиент хочет сделать с ресурсом. RFC 9110 определяет восемь методов, ещё один (PATCH) — отдельный RFC 5789.

МетодНазначениеБезопасныйИдемпотентныйТело запроса
GETполучить ресурсдадане используется
HEADто же, что GET, но только заголовкидаданет
POSTпередать данные на обработку: форма, создание объектанетнетда
PUTсоздать или целиком заменить ресурс по адресунетдада
PATCHчастично изменить ресурснетнетда
DELETEудалить ресурснетдаобычно нет
OPTIONSузнать, какие методы доступны; используется в CORSдадаобычно нет
CONNECTоткрыть туннель через прокси, чаще всего для HTTPSнетнетнет
TRACEвернуть запрос обратно для отладки; на серверах обычно выключендаданет

Безопасный метод не меняет состояние на сервере: его можно вызывать сколько угодно, ничего не сломав. Поэтому поисковые роботы и функция предзагрузки в браузере свободно ходят по ссылкам — ссылки всегда ведут на GET. Если удаление записи в админке сделано через GET /delete?id=5, рано или поздно его выполнит какой-нибудь робот или антивирус, проверяющий ссылки из писем.

Идемпотентный метод даёт тот же результат при повторе. PUT /users/5 с одинаковым телом дважды оставит пользователя в том же состоянии, а два одинаковых POST /orders создадут два заказа. Это важно для повторов: клиенты, прокси и балансировщики имеют право сами повторить идемпотентный запрос после обрыва соединения, но не POST. Отсюда предупреждение браузера «Отправить данные формы повторно?» при обновлении страницы после POST.

Тело у GET формально не запрещено, но смысла по стандарту не имеет, и многие прокси и серверы его отбрасывают. Параметры GET передаются в строке запроса.

Коды состояния

Код — трёхзначное число, первая цифра задаёт класс.

1xx — информационные. Промежуточные ответы, после которых придёт окончательный.

  • 100 Continue — сервер готов принять большое тело (клиент спрашивает об этом заголовком Expect: 100-continue; curl добавляет его сам при отправке больших тел);
  • 101 Switching Protocols — сервер переходит на другой протокол, например WebSocket (подробнее — «Переход на HTTPS и заголовок Upgrade»);
  • 103 Early Hints — ранние подсказки: сервер ещё готовит страницу, но уже сообщает, какие стили и скрипты стоит начать загружать.

2xx — успех.

  • 200 OK — обычный успешный ответ;
  • 201 Created — ресурс создан, его адрес в заголовке Location;
  • 204 No Content — успех, тела нет (частый ответ на DELETE и PUT);
  • 206 Partial Content — отдана часть файла по запросу Range; на этом работают докачка и перемотка видео.

3xx — перенаправления. Адрес, куда идти, — в заголовке Location.

  • 301 Moved Permanently и 308 Permanent Redirect — ресурс переехал навсегда; поисковики переносят вес страницы на новый адрес, браузер запоминает редирект;
  • 302 Found и 307 Temporary Redirect — временное перенаправление;
  • 304 Not Modified — ресурс не изменился, можно взять копию из кеша.

Разница между 301/302 и 308/307 в методе: при 301 и 302 браузеры исторически превращают POST в GET и теряют тело, а 307 и 308 обязывают повторить запрос тем же методом с тем же телом. Для редиректа API или формы используйте 307/308.

4xx — ошибка клиента. Запрос неправильный, повторять его без изменений бесполезно.

  • 400 Bad Request — синтаксически неверный запрос, битый JSON;
  • 401 Unauthorized — нужна аутентификация (несмотря на название, речь о том, что клиент не представился); сервер присылает заголовок WWW-Authenticate со способом входа;
  • 403 Forbidden — клиент известен, но доступа нет;
  • 404 Not Found — ресурса нет;
  • 405 Method Not Allowed — метод не поддерживается для этого адреса;
  • 408 Request Timeout — клиент слишком долго передавал запрос;
  • 409 Conflict — конфликт с текущим состоянием, например версия объекта устарела;
  • 413 Content Too Large — тело больше допустимого (в Nginx — client_max_body_size, по умолчанию 1 МБ);
  • 415 Unsupported Media Type — сервер не принимает такой Content-Type;
  • 429 Too Many Requests — сработало ограничение частоты; в заголовке Retry-After может быть время ожидания;
  • 451 Unavailable For Legal Reasons — доступ закрыт по требованию закона.

5xx — ошибка сервера. С запросом всё в порядке, сломалось на стороне сервера.

  • 500 Internal Server Error — необработанная ошибка в приложении;
  • 502 Bad Gateway — прокси или балансировщик не получил корректный ответ от приложения за ним: приложение упало, закрыло соединение или ответило мусором;
  • 503 Service Unavailable — сервис временно недоступен: перегрузка, обслуживание;
  • 504 Gateway Timeout — прокси не дождался ответа от приложения.

Коды 502 и 504 почти всегда отдаёт не само приложение, а стоящий перед ним Nginx, HAProxy или CDN. Если вы видите 502, смотрите журнал прокси — там будет причина вроде connect() failed (111: Connection refused) while connecting to upstream.

URL и что уходит на сервер

Адрес https://user@shop.example.ru:8443/catalog/phones?sort=price#reviews разбирается так:

  • https — схема, она определяет протокол и порт по умолчанию;
  • user@ — данные пользователя; браузеры их больше не поддерживают, curl превращает их в заголовок Authorization;
  • shop.example.ru — хост, его резолвят в IP через DNS и передают в Host (а при HTTPS ещё и в SNI);
  • 8443 — порт, если он не стандартный;
  • /catalog/phones — путь;
  • sort=price — строка запроса;
  • reviews — фрагмент, остаётся в браузере.

Символы вне ASCII и служебные символы в пути и параметрах кодируются процентами: пробел — %20, кириллическая «я» — %D1%8F. Кириллический домен кодируется иначе — в Punycode (пример.рф → xn--e1afmkfd.xn--p1ai), и именно в таком виде он уходит в DNS и в Host.

Соединения и keep-alive

В HTTP/1.0 на каждый запрос открывалось новое TCP-соединение. В HTTP/1.1 соединение по умолчанию остаётся открытым, и следующие запросы идут по нему же: не нужно заново проходить тройное рукопожатие TCP и, для HTTPS, рукопожатие TLS. Закрыть соединение после ответа просит заголовок Connection: close.

Запросы по одному соединению HTTP/1.1 идут строго по очереди: следующий можно отправить только после ответа на предыдущий. Поэтому браузеры открывают к одному сайту до шести соединений параллельно. Эту проблему решили HTTP/2 и HTTP/3.

HTTP и HTTPS

HTTPS — это тот же HTTP, но переданный внутри зашифрованного соединения TLS. Запрос и ответ выглядят так же, меняется транспорт: сначала клиент и сервер договариваются о ключах и проверяют сертификат, и только потом по защищённому каналу идут HTTP-сообщения. Без TLS всё, что написано выше, — адрес, cookie, пароли из форм, содержимое страниц — видит и может изменить любой узел на пути: Wi-Fi в кафе, провайдер, прокси.

Попробуйте сами

HTTP/1.1 — текстовый протокол, и запрос можно набрать вручную, без браузера и curl. Команды ниже работают в Linux и macOS.

Запрос по HTTP через nc. Каждая строка заканчивается \r\n, после заголовков — пустая строка. sleep нужен, чтобы nc не закрыл соединение раньше, чем придёт ответ:

bash
{ printf 'GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n'; sleep 2; } | nc example.com 80 | head -6
HTTP/1.1 200 OK
Date: Thu, 24 Sep 2026 04:54:21 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: close
Server: cloudflare

Уберите строку Host — сервер ответит 400 Bad Request: без неё он не знает, какой сайт вам нужен.

Тот же запрос по HTTPS. openssl s_client устанавливает TLS-соединение и передаёт в него ввод как есть:

bash
printf 'HEAD / HTTP/1.1\r\nHost: example.ru\r\nConnection: close\r\n\r\n' \
  | openssl s_client -quiet -connect example.ru:443 -servername example.ru 2>/dev/null

Методы и коды состояния. Посмотрите, как ваш сайт отвечает на разные методы и на несуществующий адрес:

bash
curl -s -o /dev/null -w '%{http_code}\n' https://example.ru/                 # 200
curl -s -o /dev/null -w '%{http_code}\n' https://example.ru/no-such-page/    # должен быть 404, а не 200
curl -s -o /dev/null -w '%{http_code}\n' -X DELETE https://example.ru/       # 405 или 403
curl -si -X OPTIONS https://example.ru/ | grep -iE '^(HTTP|allow)'            # какие методы разрешены
curl -s -o /dev/null -w '%{http_code} -> %{redirect_url}\n' http://example.ru/   # 301 на https

Если на несуществующий адрес сайт отвечает 200 со страницей «Не найдено», поисковики считают такие страницы настоящими и индексируют их — это называется soft 404, и Google Search Console отмечает такие страницы отдельно.

Сам HTTP-запрос из curl. С ключом -v видно, какие заголовки curl добавил сам, — сравните их с тем, что отправляет браузер (DevTools → Network → Headers → Request Headers):

bash
curl -sv -o /dev/null https://example.ru/ 2>&1 | grep '^>'

Типичные ошибки

  • Изменение данных через GET — робот или предзагрузка выполнит действие без ведома пользователя.
  • Редирект форм и API через 301/302 — тело POST теряется. Нужен 307 или 308.
  • 200 с текстом ошибки в теле вместо кода 4xx/5xx — мониторинг и кеши считают ответ успешным, CDN может закешировать страницу ошибки.
  • 401 вместо 403 и наоборот — клиент не понимает, нужно ли ему войти или вход не поможет.
  • Автоматический повтор POST в собственном клиенте после таймаута — двойные заказы и платежи. Для безопасного повтора используют ключ идемпотентности в заголовке (так делают платёжные API).

// Похожая задача

Если у вас похожая ситуация

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

Тема статьи

Сети и маршрутизация

MikroTik, VPN, маршрутизация, DNS, BGP, доступ и проблемы связности.

Часто с этим приходят

  • Поднять VPN и безопасный доступ в офис или облако
  • Починить маршрутизацию, DNS или нестабильный канал
  • Настроить MikroTik, firewall и внешние подключения

// Следующий шаг

Если вам нужна не только статья, а помощь по этой теме, удобнее сразу перейти в услугу. Главная и подборка материалов остаются рядом.

Открыть услуги

// Contact

Нужна помощь?

Свяжись со мной и я помогу решить проблему

Написать в Telegram

Отвечаю в течение рабочего дня (03:00–13:00 GMT)

Или оставьте заявку здесь:

Подтвердите, что вы не бот.

Написать и получить быстрый ответ