HTTP-запрос — это обычное текстовое сообщение определённой формы. Если бы у браузера была кнопка «покажи мне, что ты сейчас отправишь», мы увидели бы что-то такое:

POST /api/posts HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Accept: application/json
Content-Length: 73

{"title": "Привет, мир", "body": "Это мой первый пост.", "author": "anna"}

В этом примере есть всё, что только может быть у запроса. Разберём по кусочкам.

Стартовая строка: метод + путь + версия

Первая строка — самая важная:

POST /api/posts HTTP/1.1

  • Метод — POST. Говорит, что именно мы хотим сделать с ресурсом. Детально про методы — в модуле 3.
  • Путь — /api/posts. Адрес ресурса на сервере, без имени домена. Домен лежит ниже, в заголовке Host.
  • Версия протокола — HTTP/1.1. Сейчас в индустрии активно используются HTTP/1.1HTTP/2 и HTTP/3. Для разработки фронтенда разница в основном незаметна.

Заголовки: всё, что не данные

Следом идут заголовки — пары вида Имя: значение, по одной на строку. Их может быть один, может быть тридцать. Каждый несёт какую-то метаинформацию о запросе.

Наиболее частые в работе:

  • Host — доменное имя сервера. Браузер ставит его сам, в fetch руками задавать не надо.
  • Content-Type — формат данных в теле запроса. Для JSON это application/json, для формы — application/x-www-form-urlencoded или multipart/form-data.
  • Accept — формат, в котором мы хотим получить ответ. Сервер видит этот заголовок и решает, в чём отвечать.
  • Authorization — токен авторизации, чтобы сервер понимал, от чьего лица запрос. Подробно — в модуле 7.
  • User-Agent — идентификатор клиента (название браузера и версия). Браузер опять же ставит сам.
  • Cookie — куки, привязанные к этому домену. Браузер прикрепляет автоматически.

Большинство заголовков нам как фронтендерам трогать не нужно — браузер всё расставляет сам. В fetch руками обычно задают только Content-TypeAccept и Authorization.

Пустая строка: разделитель

Между заголовками и телом — обязательная пустая строка. Это сигнал серверу: «заголовки кончились, дальше тело». На взгляд эта деталь незаметна, но без неё сервер не понял бы, где заканчивается метаинформация.

Тело запроса: где едут данные

После пустой строки — тело (body):

{"title": "Привет, мир", "body": "Это мой первый пост.", "author": "anna"}

Тело есть не у всех запросов. Главное правило: у GET и DELETE тела обычно нет. Они должны выражать своё намерение через путь и query-параметры. У POSTPUTPATCH тело — основной носитель данных.

Формат тела определяется заголовком Content-Type. В REST API почти всегда — JSON. Бывают другие случаи: формы (для загрузки файлов), бинарные данные (например, картинка), текст. О них в модуле 5.

Query-параметры: путь со знаком вопроса

Ещё одно место, где едут данные — query-параметры в самом URL после знака вопроса:

GET /api/posts?author=anna&limit=10&page=2 HTTP/1.1

Это пары «ключ=значение», разделённые амперсандом. Обычно используются для фильтрации, пагинации, поиска — то есть всего, что уточняет «какой именно ресурс или список». Они часть пути запроса и приезжают на сервер вместе со стартовой строкой. Подробно про query-параметры — в главе 5.1.

Что в fetch мы пишем сами

Чтобы заранее настроить ожидания: когда дойдём до fetch в модуле 4, руками нам нужно будет задавать только три вещи — URL (включая query-параметры, если есть), метод и при необходимости заголовки и тело. Всё остальное (HostUser-AgentContent-LengthCookie) браузер подставит автоматически.

В следующей главе разберем зеркальную часть — что приходит в ответ.