Анатомія HTTP-запиту
Анатомія HTTP-запиту
🎯 Мета розділу
- Опанувати структуру HTTP-запиту: стартовий рядок, заголовки та тіло повідомлення.
- Навчитися читати та аналізувати RAW HTTP-запити у текстовому форматі.
- Зрозуміти призначення кожного компонента запиту та правила його формування.
- Засвоїти синтаксичні правила та обмеження протоколу HTTP/1.1.
🔑 Ключові терміни
- Request Line — стартовий рядок HTTP-запиту, що містить метод, URI та версію протоколу.
- HTTP Method — дієслово, що визначає тип операції (GET, POST, PUT, DELETE тощо).
- Request URI — адреса ресурсу, до якого звертається клієнт.
- HTTP Headers — метадані запиту у форматі ключ-значення.
- Request Body — тіло запиту, яке містить дані для передачі на сервер (опційне).
Загальна структура HTTP-запиту
HTTP-запит — це текстове повідомлення, яке клієнт відправляє серверу для ініціації взаємодії. Незважаючи на зовнішню простоту, структура запиту підпорядковується строгим синтаксичним правилам, визначеним у специфікації протоколу. Розуміння цієї структури є необхідною умовою для налагодження веб-застосунків, аналізу мережевого трафіку та розробки власних HTTP-клієнтів і серверів.
HTTP-запит складається з трьох основних частин, розділених послідовністю символів CRLF (Carriage Return + Line Feed, тобто \r\n):
- Стартовий рядок (Request Line або Start Line) — визначає метод запиту, цільовий ресурс та версію протоколу.
- Заголовки (Headers) — набір пар ключ-значення, що містять метадані про запит, клієнта та дані, що передаються.
- Тіло запиту (Request Body) — дані, які клієнт відправляє серверу (не обов'язкова частина, залежить від методу запиту).
Між заголовками та тілом запиту обов'язково має бути порожній рядок (тобто подвійна послідовність CRLF), що сигналізує серверу про завершення розділу заголовків та початок тіла.
Загальна схема HTTP-запиту
[Метод] [URI] [Версія протоколу]CRLF
[Заголовок-1]: [Значення]CRLF
[Заголовок-2]: [Значення]CRLF
...
[Заголовок-N]: [Значення]CRLF
CRLF
[Тіло запиту — опційне]
CRLF (код ASCII 0x0D 0x0A) є обов'язковими роздільниками у протоколі HTTP/1.x. Використання лише LF (\n) без CR (\r) технічно порушує специфікацію, хоча деякі сервери толерують таку поведінку. Для забезпечення сумісності завжди використовуйте повну послідовність \r\n.Стартовий рядок HTTP-запиту (Request Line)
Стартовий рядок є першим рядком HTTP-запиту і містить три обов'язкові компоненти, розділені одиночним пробілом (символ ASCII 0x20):
[HTTP-метод] [Request-URI] [HTTP-версія]
Наприклад:
GET /api/v1/products?category=laptops HTTP/1.1
Розберемо кожен компонент детально.
HTTP-метод (HTTP Method)
HTTP-метод (method або verb) — це дієслово, яке визначає тип операції, що клієнт бажає виконати над ресурсом. Метод є регістрозалежним (case-sensitive) та повинен бути записаний великими літерами.
Специфікація HTTP/1.1 визначає наступні стандартні методи:
GET— отримання ресурсу без зміни його стану.POST— створення нового ресурсу або відправка даних на обробку.PUT— повна заміна існуючого ресурсу.PATCH— часткове оновлення ресурсу.DELETE— видалення ресурсу.HEAD— отримання лише заголовків відповіді без тіла (ідентично GET, але без передачі вмісту).OPTIONS— запит підтримуваних методів та можливостей для даного ресурсу.TRACE— діагностичний метод для відстеження проміжних проксі-серверів.CONNECT— встановлення тунелю (використовується для HTTPS через проксі).
Детальний розгляд семантики кожного методу буде наведено у окремому розділі. Наразі важливо розуміти, що метод є обов'язковим елементом стартового рядка і точно визначає намір клієнта.
PATCH2 або RETRIEVE) може призвести до відхилення запиту сервером із кодом статусу 405 Method Not Allowed або 501 Not Implemented. Завжди дотримуйтесь стандартизованих методів згідно з RFC 7231.Request-URI (Uniform Resource Identifier)
Request-URI — це адреса ресурсу, до якого звертається клієнт. У найпростішому випадку це абсолютний шлях (absolute path) на сервері, що починається з символу /. URI може також містити рядок запиту (query string) та фрагмент (fragment), хоча фрагмент зазвичай не передається серверу.
Структура Request-URI
/шлях?параметр1=значення1&параметр2=значення2#фрагмент
- Шлях (
/api/v1/products) — ієрархічна структура, що ідентифікує ресурс на сервері. - Рядок запиту (
?category=laptops&sort=price) — необов'язкові параметри, розділені символом&. - Фрагмент (
#section-details) — ідентифікатор частини документа, який використовується браузером локально та не передається серверу.
Приклади валідних Request-URI
GET / HTTP/1.1
— Запит кореневого ресурсу (головної сторінки).
GET /api/v1/users/42 HTTP/1.1
— Запит інформації про користувача з ідентифікатором 42.
GET /search?q=http+protocol&lang=uk HTTP/1.1
— Пошуковий запит з параметрами q (пошуковий термін) та lang (мова).
POST /api/v1/orders HTTP/1.1
— Створення нового замовлення (дані будуть у тілі запиту).
Глибоке занурення: URI, URL та URN
Перш ніж продовжити розгляд структури HTTP-запиту, необхідно детально розібратися у термінології ідентифікації ресурсів у мережі Інтернет. Терміни URI, URL та URN часто використовуються як синоніми, але насправді вони мають чіткі відмінності та ієрархічні відношення.
URI (Uniform Resource Identifier) — Уніфікований Ідентифікатор Ресурсу
URI (Uniform Resource Identifier) — це загальний термін для будь-якого рядка символів, що однозначно ідентифікує ресурс у мережі або локально. URI є абстрактною концепцією, яка включає два підтипи: URL та URN.
Формальне визначення URI наведене у документі RFC 3986 (2005 рік), який замінив попередні специфікації RFC 2396 та RFC 1738. Згідно з цим стандартом, URI складається з п'яти компонентів:
scheme:[//authority]path[?query][#fragment]
Де:
- scheme — схема (протокол):
http,https,ftp,mailto,file,urnтощо. - authority — авторитет (опційний): інформація про сервер, зазвичай у форматі
userinfo@host:port. - path — шлях: ієрархічна послідовність сегментів, що ідентифікує ресурс.
- query — запит (опційний): додаткові параметри для ідентифікації ресурсу.
- fragment — фрагмент (опційний): посилання на підрозділ усередині ресурсу.
Приклади валідних URI:
https://www.example.com/products/laptop?id=42#specs
mailto:support@example.com
ftp://ftp.example.com/files/document.pdf
urn:isbn:978-0-596-52068-7
file:///home/user/documents/report.pdf
tel:+380501234567
URL (Uniform Resource Locator) — Уніфікований Локатор Ресурсу
URL (Uniform Resource Locator) — це підмножина URI, що не лише ідентифікує ресурс, але й вказує спосіб його отримання (місцезнаходження у мережі та протокол доступу). URL завжди містить схему та, зазвичай, авторитет (хост).
URL відповідає на питання: «Де знаходиться ресурс і як до нього отримати доступ?»
Структура типового HTTP(S) URL:
scheme://userinfo@host:port/path?query#fragment
Розберемо кожен компонент на прикладі:
https://john:secret@api.example.com:8443/v1/users/42?fields=name,email#profile
https— схема (протокол HTTPS).john:secret— userinfo (ім'я користувача та пароль для базової HTTP-автентифікації, рідко використовується через проблеми безпеки).api.example.com— хост (доменне ім'я або IP-адреса сервера).8443— порт (якщо не вказано, використовується стандартний: 80 для HTTP, 443 для HTTPS)./v1/users/42— шлях до ресурсу на сервері.?fields=name,email— рядок запиту з параметрами.#profile— фрагмент (використовується клієнтом локально, не передається серверу).
https://user:password@example.com) є небезпечною практикою, оскільки URL логуються серверами, проксі-серверами, зберігаються у історії браузера та можуть бути випадково розкриті. Завжди використовуйте заголовок Authorization для автентифікації.URN (Uniform Resource Name) — Уніфіковане Ім'я Ресурсу
URN (Uniform Resource Name) — це підмножина URI, що ідентифікує ресурс за іменем у певному просторі імен, але не вказує місцезнаходження ресурсу. URN є постійним ідентифікатором, який не змінюється навіть при переміщенні ресурсу.
URN відповідає на питання: «Що це за ресурс?» (але не «де він знаходиться»).
Структура URN:
urn:namespace:specific-string
Приклади URN:
urn:isbn:978-0-13-110362-7
— URN для книги за системою ISBN (International Standard Book Number).
urn:ietf:rfc:3986
— URN для документа RFC 3986 (специфікація URI).
urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66
— URN для унікального ідентифікатора UUID.
urn:mpeg:mpeg7:schema:2001
— URN для схеми метаданих MPEG-7.
Ключова відмінність URN від URL: URN не містить інформації про протокол доступу або місцезнаходження. Щоб отримати ресурс за URN, потрібна додаткова система розпізнавання (resolution service), яка перетворює URN на URL.
Відношення між URI, URL та URN
URI є надмножиною, що включає як URL (локатори), так і URN (імена):
URI (Uniform Resource Identifier)
┌─────────────────┴─────────────────┐
│ │
URL URN
(Locator — де і як) (Name — що це)
Аналогія з реальним світом:
- URI — загальна концепція ідентифікації людини.
- URL — домашня адреса людини: «вул. Хрещатик, 22, кв. 5, Київ, Україна» (вказує, де знайти людину).
- URN — ім'я або номер паспорта людини: «Іван Петрович Сидоренко» або «ВС 123456» (ідентифікує, хто це, але не вказує місцезнаходження).
URL-кодування (Percent-Encoding)
Якщо параметри запиту або інші частини URL містять спеціальні символи (пробіли, кирилицю, символи &, =, ?, #, / тощо), вони повинні бути закодовані за допомогою URL-кодування (percent-encoding або URL encoding). Кожен символ замінюється послідовністю %XX, де XX — шістнадцятковий код символу у UTF-8.
Зарезервовані символи у URI (мають спеціальне значення):
: / ? # [ ] @ ! $ & ' ( ) * + , ; =
Незарезервовані символи (можна використовувати без кодування):
A-Z a-z 0-9 - . _ ~
Приклади URL-кодування:
| Оригінальний символ | URL-кодування | Пояснення |
|---|---|---|
Пробіл | %20 або + | + використовується лише у query string |
# | %23 | Зарезервований для фрагментів |
& | %26 | Зарезервований для розділення параметрів |
= | %3D | Зарезервований для присвоєння значень |
п (кирилиця) | %D0%BF | UTF-8 кодування кирилиці (2 байти) |
🚀 (emoji) | %F0%9F%9A%80 | UTF-8 кодування emoji (4 байти) |
Приклад запиту з URL-кодуванням:
GET /search?q=%D0%BF%D1%80%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%BB+HTTP&lang=uk&page=1 HTTP/1.1
Host: search.example.com
Тут рядок протокол HTTP (з пробілом) був закодований:
протокол→%D0%BF%D1%80%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%BB- Пробіл →
+(або%20) HTTPзалишається без змін (латиниця та цифри не потребують кодування)
Сервер автоматично декодує ці значення перед обробкою: q=протокол HTTP.
fetch, axios, curl) автоматично виконують URL-кодування параметрів. При ручному формуванні запитів переконайтеся, що всі спеціальні символи правильно закодовані, інакше сервер може неправильно інтерпретувати параметри або відхилити запит із кодом 400 Bad Request.Детальна структура URL на прикладі
Розглянемо повний URL із усіма можливими компонентами та проаналізуємо кожну частину:
https://admin:P@ssw0rd@api.shop.example.com:8443/api/v2/products/search?category=laptops&brand=dell&price_max=50000&sort=price_asc&page=3#results
Розбір компонентів:
https://— Схема (протокол HTTPS, захищений SSL/TLS).admin:P@ssw0rd@— UserInfo (⚠️ не рекомендується через витоки у логах).api.shop.example.com— Хост (субдоменapi.shopдоменуexample.com).:8443— Порт (нестандартний, зазвичай HTTPS використовує 443)./api/v2/products/search— Шлях до API-ендпоінта (версія v2, ресурс products, операція search).?category=laptops&brand=dell&price_max=50000&sort=price_asc&page=3— Query string з фільтрами та пагінацією.#results— Фрагмент для прокрутки до секції результатів (обробляється браузером, не надсилається серверу).
Відносні та абсолютні URI у HTTP
У HTTP-запитах URI може бути представлений у кількох формах:
1. Відносний URI (найпоширеніший у HTTP/1.1)
GET /api/v1/users/42 HTTP/1.1
Host: api.example.com
Тут /api/v1/users/42 — це відносний шлях. Повний URL реконструюється сервером на основі заголовка Host:
https://api.example.com/api/v1/users/42
(Схема https визначається тим, чи використовується TLS-з'єднання).
2. Абсолютний URI (для проксі-серверів)
При роботі через HTTP-проксі клієнт може надіслати повний абсолютний URI зі схемою та хостом:
GET http://api.example.com/api/v1/users/42 HTTP/1.1
Host: api.example.com
Проксі-сервер аналізує повний URI, встановлює з'єднання з цільовим хостом та передає запит.
3. Authority Form (для методу CONNECT)
Використовується виключно для методу CONNECT при встановленні HTTPS-тунелю через проксі:
CONNECT api.example.com:443 HTTP/1.1
Host: api.example.com
4. Asterisk Form (для методу OPTIONS)
Спеціальна форма * для запиту можливостей сервера загалом (не конкретного ресурсу):
OPTIONS * HTTP/1.1
Host: api.example.com
Фрагмент (fragment identifier, частина URL після символу #) є компонентом, призначеним виключно для клієнтської обробки. Його основне призначення — вказати браузеру на конкретну частину документа (наприклад, секцію сторінки, заголовок, елемент з певним id).
Чому не передається серверу:
- Семантика протоколу HTTP: Сервер відповідає за надання цілого ресурсу (HTML-документ, JSON-відповідь). Фрагмент визначає, яку частину цього ресурсу відобразити користувачеві, але сам ресурс залишається незмінним незалежно від фрагмента.
- Продуктивність: Якби фрагменти передавалися серверу, кожен перехід до різних секцій однієї сторінки вимагав би повторного HTTP-запиту. Натомість браузер завантажує сторінку один раз та локально прокручує до потрібної секції.
- Конфіденційність: Фрагменти можуть містити чутливу інформацію (наприклад, токени автентифікації у Single Page Applications). Якби вони передавалися серверу, вони б логувалися проксі-серверами та потрапляли у логи сервера.
Приклад:
https://docs.example.com/api-guide.html#authentication
- Браузер запитує у сервера:
GET /api-guide.html HTTP/1.1 - Сервер повертає весь HTML-документ.
- Браузер локально знаходить елемент з
id="authentication"та прокручує до нього.
Виняток: У Single Page Applications (React, Vue, Angular) фрагменти часто використовуються для клієнтської маршрутизації (наприклад, /#/products/42). JavaScript-код застосунку аналізує фрагмент та динамічно завантажує відповідний вміст через AJAX/Fetch API.
IRI (Internationalized Resource Identifier, RFC 3987) — це розширення URI, яке дозволяє використовувати символи Unicode безпосередньо у ідентифікаторі ресурсу без попереднього percent-encoding.
URI:
https://example.com/search?q=%D0%BF%D1%80%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%BB
IRI (той самий ресурс):
https://example.com/search?q=протокол
Переваги IRI:
- Читабельність для людини (особливо для нелатинських мов).
- Природне представлення інтернаціоналізованих доменних імен (IDN).
Обмеження:
- IRI повинен бути перетворений на URI перед передачею через HTTP (шляхом percent-encoding).
- Не всі системи підтримують IRI нативно.
Сучасні браузери автоматично конвертують IRI у URI перед відправкою запиту, тому користувачі можуть вводити URL кирилицею в адресному рядку, а браузер закодує їх для HTTP.
---У деяких випадках (зокрема, при роботі через HTTP-проксі) клієнт може використовувати абсолютну форму URI, яка включає схему та хост:
GET http://www.example.com/api/v1/products HTTP/1.1
Host: www.example.com
Проте у більшості випадків використовується відносна форма (лише шлях), а ім'я хоста вказується в обов'язковому заголовку Host.
HTTP-версія (HTTP-Version)
Третій компонент стартового рядка — це версія протоколу HTTP, яку клієнт використовує для комунікації. Версія записується у форматі:
HTTP/major.minor
де major — основний номер версії, minor — додатковий номер версії.
Підтримувані версії
HTTP/0.9— застаріла, підтримка відсутня у сучасних серверах.HTTP/1.0— рідко використовується, підтримується для зворотної сумісності.HTTP/1.1— стандарт де-факто, повсюдна підтримка.HTTP/2.0— технічно записується якHTTP/2, але у стартовому рядку HTTP/2 не використовується текстовий формат (бінарне кадрування).HTTP/3.0— аналогічно,HTTP/3також не використовує текстовий стартовий рядок.
Приклад повного стартового рядка
GET /api/v1/users/search?name=John&role=admin HTTP/1.1
Цей рядок інформує сервер про те, що:
- Клієнт бажає отримати (
GET) дані (без зміни стану сервера). - Цільовий ресурс —
/api/v1/users/searchз параметрамиname=Johnтаrole=admin. - Клієнт використовує протокол HTTP версії 1.1 і очікує, що сервер підтримує цю версію.
Заголовки HTTP-запиту (Request Headers)
Після стартового рядка йде розділ заголовків (headers) — набір пар ключ-значення, що надають серверу додаткову інформацію про запит, клієнта, дані, що передаються, та очікувану поведінку. Кожен заголовок займає окремий рядок і має формат:
Назва-Заголовка: Значення
- Назва заголовка є регістронезалежною (case-insensitive), тобто
Content-Type,content-typeтаCONTENT-TYPEінтерпретуються однаково. - Значення заголовка зазвичай є регістрозалежним (залежить від конкретного заголовка).
- Після назви заголовка слідує двокрапка (
:) та пробіл (пробіл після двокрапки опційний згідно зі специфікацією, але рекомендується для читабельності). - Кожен заголовок завершується послідовністю
CRLF.
Класифікація заголовків
Заголовки HTTP можна класифікувати за призначенням:
- Загальні заголовки (General Headers) — застосовні як до запитів, так і до відповідей (наприклад,
Date,Connection,Cache-Control). - Заголовки запиту (Request Headers) — специфічні для запитів, містять інформацію про клієнта та бажаний формат відповіді (наприклад,
Host,User-Agent,Accept,Authorization). - Заголовки сутності (Entity Headers) — описують тіло повідомлення (наприклад,
Content-Type,Content-Length,Content-Encoding). - Нестандартні заголовки — розширення, що не входять у специфікацію HTTP, але широко використовуються (зазвичай починаються з префікса
X-, хоча ця конвенція застаріла).
Обов'язкові заголовки у HTTP/1.1
У HTTP/1.1 існує лише один обов'язковий заголовок у кожному запиті:
Host — ім'я хоста та порт сервера
Host: www.example.com
або з явним зазначенням порту:
Host: api.example.com:8080
Заголовок Host є критичним для віртуального хостингу (virtual hosting), коли один фізичний сервер з однією IP-адресою обслуговує множину доменів. Сервер аналізує значення Host, щоб визначити, який веб-сайт повинен обробити запит.
Host у HTTP/1.1 запиті є порушенням специфікації і зазвичай призводить до відповіді сервера з кодом статусу 400 Bad Request. У HTTP/1.0 цей заголовок був опційним, але у HTTP/1.1 він став обов'язковим саме через необхідність підтримки віртуального хостингу.Поширені заголовки запиту
Розглянемо найчастіше використовувані заголовки у HTTP-запитах:
User-Agent — ідентифікація клієнта
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
Цей заголовок містить інформацію про програмне забезпечення клієнта: назву браузера, версію, операційну систему, рушій рендерингу. Сервери можуть використовувати цю інформацію для адаптації відповіді (наприклад, відправка спрощеної версії сторінки для старих браузерів) або для збору статистики.
Accept — бажаний формат відповіді
Accept: application/json, text/html;q=0.9, */*;q=0.8
Заголовок Accept інформує сервер про те, які MIME-типи (media types) клієнт може обробити. Можна вказати множину типів з пріоритетами через параметр q (якість, від 0 до 1). У прикладі вище клієнт найбільше воліє application/json, потім text/html (з пріоритетом 0.9), і як крайній випадок — будь-який інший тип (*/* з пріоритетом 0.8).
Accept-Language — бажана мова відповіді
Accept-Language: uk-UA,uk;q=0.9,en-US;q=0.8,en;q=0.7
Клієнт повідомляє серверу, які мови він підтримує, у порядку пріоритету. Сервер може використовувати цю інформацію для інтернаціоналізації (i18n) та відправки вмісту відповідною мовою.
Accept-Encoding — підтримувані алгоритми стиснення
Accept-Encoding: gzip, deflate, br
Клієнт повідомляє, які алгоритми стиснення він підтримує. Сервер може стиснути тіло відповіді за допомогою одного з цих алгоритмів (наприклад, gzip або brotli), що значно зменшує обсяг переданих даних.
Authorization — автентифікаційні дані
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Цей заголовок використовується для передачі токенів автентифікації (JWT, OAuth tokens) або базової HTTP-автентифікації. Формат значення залежить від схеми автентифікації (Basic, Bearer, Digest тощо).
Cookie — передача cookies серверу
Cookie: sessionId=abc123xyz; userId=42; theme=dark
Заголовок Cookie містить пари ключ-значення, які браузер автоматично прикріплює до кожного запиту до даного домену. Cookies зазвичай використовуються для збереження ідентифікаторів сесій, налаштувань користувача та іншої інформації про стан.
Referer — адреса попередньої сторінки
Referer: https://www.google.com/search?q=http+protocol
Заголовок Referer (помилково написаний у специфікації, правильно було б Referrer) містить URL сторінки, з якої користувач перейшов на поточний ресурс. Сервери можуть використовувати цю інформацію для аналітики, захисту від гарячого лінкування (hotlinking) або перевірки джерела трафіку.
Referer відповідно до політики Referrer-Policy. Наприклад, при переході з HTTPS-сайту на HTTP-сайт заголовок Referer може бути видалений для запобігання витоку інформації.Connection — керування з'єднанням
Connection: keep-alive
або
Connection: close
Заголовок Connection визначає, чи повинно TCP-з'єднання залишатися відкритим після завершення запиту (keep-alive) чи бути закритим (close). У HTTP/1.1 значення keep-alive є поведінкою за замовчуванням, тому явне зазначення цього заголовка часто опускається.
Content-Type — тип даних у тілі запиту
Content-Type: application/json; charset=utf-8
Цей заголовок вказує серверу, який MIME-тип має тіло запиту. Він обов'язковий для запитів, які передають дані у тілі (POST, PUT, PATCH). Поширені значення:
application/json— JSON-дані.application/x-www-form-urlencoded— дані HTML-форми (ключ=значення, URL-кодування).multipart/form-data— дані форми з файлами (використовується для завантаження файлів).text/plain— простий текст.application/xml— XML-документ.
Content-Length — розмір тіла запиту
Content-Length: 348
Заголовок Content-Length містить довжину тіла запиту у байтах. Він є обов'язковим для запитів із тілом, якщо не використовується механізм передачі по частинах (chunked transfer encoding). Сервер використовує це значення для визначення, скільки байтів потрібно прочитати з TCP-потоку після заголовків.
Content-Length та фактичним розміром тіла може призвести до помилок парсингу запиту, обриву з'єднання або вразливості до атак контрабанди запитів (HTTP request smuggling). Завжди переконайтеся у точності цього значення.Приклад повного набору заголовків
POST /api/v1/auth/login HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: application/json
Accept-Language: uk-UA,uk;q=0.9
Accept-Encoding: gzip, deflate, br
Content-Type: application/json; charset=utf-8
Content-Length: 58
Connection: keep-alive
Origin: https://frontend.example.com
Цей набір заголовків супроводжує POST-запит для автентифікації користувача. Зверніть увагу на порожній рядок після останнього заголовка — він сигналізує про завершення розділу заголовків та початок тіла запиту.
Тіло HTTP-запиту (Request Body)
Тіло запиту (request body або message body) містить дані, які клієнт відправляє серверу для обробки. Не всі HTTP-методи передбачають наявність тіла:
- Методи без тіла (зазвичай):
GET,HEAD,DELETE,OPTIONS. - Методи з тілом:
POST,PUT,PATCH.
Тіло запиту розташовується після порожнього рядка, який слідує за останнім заголовком. Формат та структура тіла визначаються заголовком Content-Type.
Формати тіла запиту
1. JSON (application/json)
JSON є найпоширенішим форматом для сучасних REST API завдяки своїй читабельності, компактності та природній підтримці в усіх мовах програмування.
Повний приклад запиту:
POST /api/v1/users HTTP/1.1
Host: api.example.com
User-Agent: curl/7.88.0
Accept: application/json
Content-Type: application/json; charset=utf-8
Content-Length: 98
{"email":"john.doe@example.com","password":"SecurePass123!","firstName":"John","lastName":"Doe"}
Аналіз:
- Стартовий рядок:
POST /api/v1/users HTTP/1.1— створення нового користувача. - Заголовок
Content-Type: application/json— інформує сервер, що тіло містить JSON. - Заголовок
Content-Length: 98— розмір тіла (98 байтів). - Тіло: JSON-об'єкт із даними нового користувача.
Сервер парсить JSON, валідує поля (email, password) та створює запис у базі даних.
2. Form Data (application/x-www-form-urlencoded)
Цей формат використовується HTML-формами за замовчуванням, коли не передаються файли. Дані кодуються аналогічно до рядка запиту в URL: пари ключ=значення, розділені символом &.
Повний приклад запиту:
POST /api/v1/auth/login HTTP/1.1
Host: secure.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: text/html,application/xhtml+xml
Content-Type: application/x-www-form-urlencoded
Content-Length: 53
email=admin%40example.com&password=MyPassword%21%402024
Аналіз:
- Тіло:
email=admin%40example.com&password=MyPassword%21%402024 - Символи
@,!закодовані як%40,%21відповідно. - Сервер декодує дані та перевіряє облікові дані для входу.
3. Multipart Form Data (multipart/form-data)
Використовується для завантаження файлів разом із текстовими полями. Тіло розбивається на частини (parts), кожна з яких має власні заголовки та вміст. Частини розділяються унікальною межею (boundary).
Повний приклад запиту:
POST /api/v1/documents/upload HTTP/1.1
Host: files.example.com
User-Agent: curl/7.88.0
Accept: */*
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Length: 456
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="title"
Monthly Report
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="report.pdf"
Content-Type: application/pdf
[бінарні дані файлу PDF]
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Аналіз:
- Заголовок
Content-Typeмістить параметрboundary, який визначає роздільник між частинами. - Кожна частина має власний заголовок
Content-Disposition, що вказує ім'я поля форми (name) та, опційно, ім'я файлу (filename). - Остання межа завершується подвійним дефісом (
--), сигналізуючи про кінець тіла.
4. Plain Text (text/plain)
Рідко використовується для API, але може застосовуватися для відправки логів, текстових повідомлень або простих даних.
Повний приклад запиту:
POST /api/v1/logs HTTP/1.1
Host: logging.example.com
Content-Type: text/plain; charset=utf-8
Content-Length: 124
2026-08-29 10:30:00 ERROR [DatabaseService] Connection timeout after 5000ms. Host: db.example.com:5432, Retry attempt: 3/5
5. XML (application/xml)
Використовується у старих API або системах інтеграції (SOAP, legacy enterprise systems).
Повний приклад запиту:
POST /api/v1/orders HTTP/1.1
Host: shop.example.com
Content-Type: application/xml; charset=utf-8
Content-Length: 256
<?xml version="1.0" encoding="UTF-8"?>
<order>
<customer>
<id>42</id>
<email>customer@example.com</email>
</customer>
<items>
<item productId="101" quantity="2"/>
<item productId="205" quantity="1"/>
</items>
</order>
Повні RAW приклади HTTP-запитів для різних сценаріїв
Для закріплення розуміння структури HTTP-запиту розглянемо декілька типових сценаріїв веб-розробки з повними RAW запитами.
Приклад 1: Отримання списку товарів (GET з параметрами)
Сценарій: Клієнт (веб-застосунок електронної комерції) запитує список ноутбуків, відсортованих за ціною, із пагінацією.
GET /api/v1/products?category=laptops&sort=price&order=asc&page=2&limit=20 HTTP/1.1
Host: shop.example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36
Accept: application/json
Accept-Language: uk-UA,uk;q=0.9
Accept-Encoding: gzip, deflate, br
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjQyLCJyb2xlIjoidXNlciJ9.abc123
Connection: keep-alive
Cache-Control: no-cache
Ключові моменти:
- Метод
GET— безпечний та ідемпотентний, не змінює стан сервера. - Параметри запиту (
category,sort,order,page,limit) передаються у URL. - Заголовок
Authorizationмістить JWT-токен для автентифікації. - Заголовок
Cache-Control: no-cacheвказує, що клієнт хоче отримати свіжі дані, обходячи кеш. - Тіло запиту відсутнє (порожній рядок після заголовків).
Приклад 2: Створення нового замовлення (POST з JSON)
Сценарій: Користувач завершує процес оформлення замовлення, відправляючи дані про кошик, адресу доставки та спосіб оплати.
POST /api/v1/orders HTTP/1.1
Host: api.shop.example.com
User-Agent: ShoppingApp/2.5.0 (iOS 17.0)
Accept: application/json
Content-Type: application/json; charset=utf-8
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyMywicm9sZSI6ImN1c3RvbWVyIn0.xyz789
Content-Length: 387
{
"userId": 123,
"items": [
{"productId": 501, "quantity": 2, "price": 25000},
{"productId": 612, "quantity": 1, "price": 15000}
],
"shippingAddress": {
"street": "Шевченка, 42",
"city": "Київ",
"postalCode": "01001",
"country": "Україна"
},
"paymentMethod": "credit_card",
"totalAmount": 65000
}
Ключові моменти:
- Метод
POST— створення нового ресурсу (замовлення). - Тіло містить структурований JSON з вкладеними об'єктами (адреса доставки, список товарів).
- Заголовок
Content-Length: 387точно відповідає розміру JSON-тіла у байтах (включаючи пробіли та переноси рядків). - Сервер після обробки поверне код статусу
201 Createdз ідентифікатором створеного замовлення.
Приклад 3: Оновлення профілю користувача (PATCH)
Сценарій: Користувач змінює своє ім'я та номер телефону через форму налаштувань профілю.
PATCH /api/v1/users/42 HTTP/1.1
Host: api.example.com
User-Agent: curl/7.88.0
Accept: application/json
Content-Type: application/json; charset=utf-8
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjQyLCJyb2xlIjoidXNlciJ9.token123
Content-Length: 68
{
"firstName": "Іван",
"phone": "+380501234567"
}
Ключові моменти:
- Метод
PATCH— часткове оновлення ресурсу (на відміну відPUT, який замінює ресурс повністю). - URI містить ідентифікатор користувача (
/users/42), який оновлюється. - Тіло містить лише ті поля, які потрібно змінити (інші поля профілю залишаються незмінними).
Приклад 4: Видалення ресурсу (DELETE)
Сценарій: Адміністратор видаляє застарілу статтю з блогу.
DELETE /api/v1/articles/87 HTTP/1.1
Host: blog.example.com
User-Agent: AdminPanel/1.0
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInJvbGUiOiJhZG1pbiJ9.adminToken
Content-Length: 0
Ключові моменти:
- Метод
DELETE— видалення ресурсу. - Тіло запиту відсутнє (
Content-Length: 0). - Заголовок
Authorizationмістить токен адміністратора з відповідними правами доступу. - Сервер поверне
204 No Content(успішне видалення без тіла відповіді) або200 OKз підтвердженням.
Приклад 5: Preflight-запит OPTIONS (CORS)
Сценарій: Браузер відправляє preflight-запит перед POST-запитом до API на іншому домені для перевірки дозволів CORS.
OPTIONS /api/v1/users HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: */*
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization
Origin: https://frontend.example.com
Ключові моменти:
- Метод
OPTIONS— запит можливостей сервера для даного ресурсу. - Заголовки
Access-Control-Request-*інформують сервер, який метод та заголовки буде використано у реальному запиті. - Сервер відповідає заголовками
Access-Control-Allow-*, дозволяючи або забороняючи запит.
Візуалізація структури HTTP-запиту
Для кращого розуміння ієрархії компонентів HTTP-запиту наведемо діаграму:
Підсумок розділу
📚 Основні висновки
- HTTP-запит складається з трьох частин: стартового рядка, заголовків та опційного тіла.
- Стартовий рядок містить метод, Request-URI та версію протоколу, розділені пробілами.
- Заголовки надають серверу метадані про клієнта, бажаний формат відповіді, автентифікацію та характеристики тіла запиту.
- Заголовок
Hostє обов'язковим у HTTP/1.1 для підтримки віртуального хостингу. - Тіло запиту використовується у методах POST, PUT, PATCH для передачі даних, формат якихвизначається заголовком
Content-Type. - Коректне формування
Content-Lengthє критичним для безпеки та правильної обробки запиту.
🎓 Навички, набуті у розділі
- Читання та аналіз RAW HTTP-запитів у текстовому форматі.
- Розуміння призначення кожного заголовка та його впливу на обробку запиту.
- Вміння формувати валідні HTTP-запити для різних сценаріїв (GET, POST, PATCH, DELETE).
- Знання різних форматів тіла запиту (JSON, Form Data, Multipart, XML) та коректне використання
Content-Type.
Контрольні запитання для самоперевірки
У HTTP/1.0 заголовок Host був опційним, оскільки припускалося, що кожен веб-сервер обслуговує лише один домен на одній IP-адресі. Проте зі зростанням кількості веб-сайтів та дефіцитом IPv4-адрес виникла потреба у віртуальному хостингу (virtual hosting) — можливості розміщувати множину доменів на одному фізичному сервері.
HTTP/1.1 зробив заголовок Host обов'язковим, щоб сервер міг визначити, до якого саме домену звертається клієнт. Без цього заголовка сервер не зміг би розрізнити запити до site1.example.com та site2.example.com, якщо обидва домени мають однакову IP-адресу.
Невідповідність між заявленою довжиною у Content-Length та реальним розміром тіла може призвести до серйозних проблем:
- Якщо Content-Length менше за реальний розмір: Сервер прочитає лише частину тіла, вважаючи запит завершеним. Залишкові дані залишаться у TCP-буфері та можуть бути інтерпретовані як початок наступного запиту, що призведе до помилок парсингу.
- Якщо Content-Length більше за реальний розмір: Сервер очікуватиме на додаткові дані, які ніколи не надійдуть, що призведе до таймауту з'єднання.
- Вразливість до атак: Навмисне маніпулювання
Content-Lengthможе використовуватися для атак HTTP Request Smuggling, коли зловмисник обманює проксі-сервери та backend-сервери, змушуючи їх по-різному інтерпретувати межі HTTP-запитів.
Завжди переконайтеся, що Content-Length точно відповідає розміру тіла у байтах.
Специфікація HTTP не забороняє передачу тіла у GET-запитах, але сильно не рекомендує це робити з кількох причин:
- Семантика методу GET: Метод GET призначений для безпечного отримання ресурсу без зміни стану сервера. Він має бути ідемпотентним та кешованим. Тіло запиту суперечить цій семантиці, оскільки воно асоціюється з модифікацією даних.
- Кешування: HTTP-кеші (проксі-сервери, CDN, браузерні кеші) використовують URL (включно з параметрами запиту) як ключ для кешування. Якщо параметри знаходяться у тілі, кеші не зможуть правильно ідентифікувати унікальність запиту.
- Сумісність: Багато серверів, проксі та бібліотек ігнорують тіло GET-запиту або взагалі відхиляють такі запити. Це може призвести до несподіваної поведінки.
- Прозорість: Параметри у URL є видимими у логах сервера, браузерній історії та інструментах розробника, що полегшує налагодження.
Для передачі великих обсягів даних або конфіденційної інформації використовуйте метод POST з тілом запиту.
Ці два заголовки часто плутають, але вони мають протилежні призначення:
Accept(заголовок запиту): Клієнт повідомляє серверу, які типи даних він може обробити у відповіді. Наприклад,Accept: application/jsonозначає: «Я воліюотримати відповідь у форматі JSON».Content-Type(заголовок запиту та відповіді): Повідомляє, який тип даних міститься у тілі поточного повідомлення. У запиті це тип даних, які клієнт відправляє серверу. У відповіді — тип даних, які сервер повертає клієнту.
Приклад:
POST /api/v1/users HTTP/1.1
Accept: application/json
Content-Type: application/json
{"name": "John"}
Тут клієнт відправляє дані у форматі JSON (Content-Type) та очікує отримати відповідь у форматі JSON (Accept).
У наступному розділі ми розглянемо анатомію HTTP-відповіді — структуру статусного рядка, заголовків відповіді та тіла, а також проаналізуємо, як сервер формує відповіді для різних запитів та кодів статусу.