Протокол HTTP та захищена передача даних HTTPS

Анатомія 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):

  1. Стартовий рядок (Request Line або Start Line) — визначає метод запиту, цільовий ресурс та версію протоколу.
  2. Заголовки (Headers) — набір пар ключ-значення, що містять метадані про запит, клієнта та дані, що передаються.
  3. Тіло запиту (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 — фрагмент (використовується клієнтом локально, не передається серверу).
Небезпека передачі облікових даних у URL: Включення паролів безпосередньо у URL (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 використовується частіше за URI або URN, оскільки у HTTP ми майже завжди оперуємо локаторами (вказуємо, де знаходиться ресурс та як його отримати). Проте згідно з термінологією специфікацій, правильніше говорити Request-URI, оскільки у деяких випадках це може бути не повний URL, а лише шлях.

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%BFUTF-8 кодування кирилиці (2 байти)
🚀 (emoji)%F0%9F%9A%80UTF-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.

Сучасні 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
Loading diagram...
@startuml
skinparam style plain
skinparam backgroundColor #FFFFFF

rectangle "Повний URL" #E0F2FE {
    rectangle "https://" as scheme #DBEAFE
    rectangle "admin:P@ssw0rd@" as userinfo #FEF3C7
    rectangle "api.shop.example.com" as host #DCFCE7
    rectangle ":8443" as port #FEF9E7
    rectangle "/api/v2/products/search" as path #E0E7FF
    rectangle "?category=laptops&brand=dell&price_max=50000&sort=price_asc&page=3" as query #FCE7F3
    rectangle "#results" as fragment #F0FDF4
}

note right of scheme
  **Схема (Scheme):**
  Протокол доступу до ресурсу.
  Стандартні порти: HTTP=80, HTTPS=443.
end note

note right of userinfo
  **UserInfo (⚠️ небезпечно):**
  Облікові дані для базової автентифікації.
  Рідко використовується, краще Authorization.
end note

note right of host
  **Хост (Host):**
  Доменне ім'я або IP-адреса сервера.
  Може бути IPv4, IPv6 або домен.
end note

note right of port
  **Порт (Port):**
  TCP-порт сервера. Опційний,
  якщо не вказано — використовується
  стандартний для схеми (80/443).
end note

note right of path
  **Шлях (Path):**
  Ієрархічна структура сегментів,
  що ідентифікує ресурс на сервері.
  Обов'язковий компонент.
end note

note right of query
  **Рядок запиту (Query String):**
  Додаткові параметри у форматі
  ключ=значення, розділені &.
  Опційний компонент.
end note

note right of fragment
  **Фрагмент (Fragment):**
  Посилання на підрозділ документа.
  **НЕ передається серверу**, обробляється
  локально клієнтом (браузером).
end note

@enduml

Розбір компонентів:

  1. https:// — Схема (протокол HTTPS, захищений SSL/TLS).
  2. admin:P@ssw0rd@ — UserInfo (⚠️ не рекомендується через витоки у логах).
  3. api.shop.example.com — Хост (субдомен api.shop домену example.com).
  4. :8443 — Порт (нестандартний, зазвичай HTTPS використовує 443).
  5. /api/v2/products/search — Шлях до API-ендпоінта (версія v2, ресурс products, операція search).
  6. ?category=laptops&brand=dell&price_max=50000&sort=price_asc&page=3 — Query string з фільтрами та пагінацією.
  7. #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

---У деяких випадках (зокрема, при роботі через 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 також не використовує текстовий стартовий рядок.
HTTP/2 та HTTP/3 використовують бінарний протокол на рівні транспорту, тому поняття «стартового рядка» у текстовому форматі до них не застосовується. Натомість вони передають ті самі семантичні дані (метод, шлях, версію) у вигляді бінарних кадрів (frames). У цьому розділі ми зосереджуємося на HTTP/1.1, який залишається базовим для розуміння архітектури протоколу.

Приклад повного стартового рядка

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 можна класифікувати за призначенням:

  1. Загальні заголовки (General Headers) — застосовні як до запитів, так і до відповідей (наприклад, Date, Connection, Cache-Control).
  2. Заголовки запиту (Request Headers) — специфічні для запитів, містять інформацію про клієнта та бажаний формат відповіді (наприклад, Host, User-Agent, Accept, Authorization).
  3. Заголовки сутності (Entity Headers) — описують тіло повідомлення (наприклад, Content-Type, Content-Length, Content-Encoding).
  4. Нестандартні заголовки — розширення, що не входять у специфікацію 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: 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-запиту наведемо діаграму:

Loading diagram...
@startuml
skinparam style plain
skinparam backgroundColor #FFFFFF

package "HTTP Request" #E0F2FE {
    rectangle "Request Line (Стартовий рядок)" #DBEAFE {
        rectangle "Method\nGET / POST / PUT / DELETE" as Method #BAE6FD
        rectangle "Request-URI\n/api/v1/products?category=laptops" as URI #BAE6FD
        rectangle "HTTP Version\nHTTP/1.1" as Version #BAE6FD
    }
    
    rectangle "Headers (Заголовки)" #FEF3C7 {
        rectangle "Host: api.example.com" as H1 #FEF9E7
        rectangle "User-Agent: Mozilla/5.0 ..." as H2 #FEF9E7
        rectangle "Accept: application/json" as H3 #FEF9E7
        rectangle "Content-Type: application/json" as H4 #FEF9E7
        rectangle "Content-Length: 123" as H5 #FEF9E7
        rectangle "Authorization: Bearer ..." as H6 #FEF9E7
    }
    
    rectangle "Empty Line (Порожній рядок CRLF)" #F1F5F9
    
    rectangle "Body (Тіло запиту — опційне)" #DCFCE7 {
        rectangle "JSON / Form Data / XML / Binary" as Body #ECFDF5
    }
}

Method -down-> URI : пробіл
URI -down-> Version : пробіл
Version -down-> H1 : CRLF
H1 -down-> H2 : CRLF
H2 -down-> H3 : CRLF
H3 -down-> H4 : CRLF
H4 -down-> H5 : CRLF
H5 -down-> H6 : CRLF
H6 -down-> "Empty Line (Порожній рядок CRLF)" : CRLF
"Empty Line (Порожній рядок CRLF)" -down-> Body : опційно

note right of "Request Line (Стартовий рядок)"
  Обов'язкова частина кожного HTTP-запиту.
  Визначає намір клієнта, цільовий ресурс
  та версію протоколу.
end note

note right of "Headers (Заголовки)"
  Метадані запиту у форматі ключ:значення.
  Принаймні заголовок Host є обов'язковим
  у HTTP/1.1.
end note

note right of Body
  Тіло запиту присутнє лише у методах
  POST, PUT, PATCH. Формат визначається
  заголовком Content-Type.
end note

@enduml

Підсумок розділу

📚 Основні висновки

  • 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-відповіді — структуру статусного рядка, заголовків відповіді та тіла, а також проаналізуємо, як сервер формує відповіді для різних запитів та кодів статусу.

Copyright © 2026