Пошук уроків, статей та іншого контенту
Розберете будову HTTP-запиту й відповіді, ролі клієнта та сервера, а також основні етапи обміну даними.
HTTP (HyperText Transfer Protocol) — протокол обміну даними між клієнтом і сервером.
За допомогою HTTP програми можуть:
отримувати вебсторінки;
завантажувати зображення, стилі та скрипти;
надсилати дані форм;
взаємодіяти з API;
створювати, змінювати й видаляти дані на сервері.
HTTP працює за моделлю «запит — відповідь»:
клієнт надсилає запит;
сервер обробляє його;
сервер повертає відповідь.
Наприклад, коли ви відкриваєте вебсторінку, браузер надсилає HTTP-запит до сервера. Сервер повертає HTML-документ, а браузер відображає його користувачу.
Клієнт — програма, яка надсилає запити до сервера.
Приклади клієнтів:
веббраузер;
мобільний застосунок;
JavaScript-код із fetch;
програма командного рядка;
інший сервер, який звертається до API.
Клієнт зазвичай повідомляє:
яку дію потрібно виконати;
додаткові параметри;
дані, які потрібно передати серверу.
Сервер — програма, яка приймає запити, обробляє їх і формує відповіді.
Сервер може:
перевірити права доступу;
прочитати дані з бази даних;
виконати бізнес-логіку;
створити або змінити ресурс;
повернути HTML, JSON, файл або повідомлення про помилку.
Важливо розрізняти сервер як комп’ютер і сервер як програму. Один фізичний комп’ютер може запускати багато серверних програм.
HTTP-запит надсилається за певною адресою — URL.
Приклад:
https://example.com:443/users?page=2Основні частини URL:
https — протокол;
example.com — доменне ім’я сервера;
443 — порт;
/users — шлях до ресурсу;
?page=2 — параметри запиту.
Порт може бути не вказаний явно. Для HTTP типовим є порт 80, а для HTTPS — 443.
Шлях описує ресурс:
/users
/users/42
/products/15/reviewsПараметри після символу ? називають query-параметрами:
/products?category=books&limit=10У цьому прикладі:
category має значення books;
limit має значення 10.
Параметри часто використовують для:
фільтрації;
сортування;
пошуку;
пагінації;
передавання необов’язкових налаштувань.
HTTP-запит складається з:
стартового рядка;
заголовків;
порожнього рядка;
необов’язкового тіла.
Приклад запиту:
POST /users HTTP/1.1
Host: example.com
Content-Type: application/json
Accept: application/json
{"name":"Olena","email":"olena@example.com"}Перший рядок має вигляд:
МЕТОД ШЛЯХ ВЕРСІЯ_HTTPУ прикладі:
POST — HTTP-метод;
/users — шлях;
HTTP/1.1 — версія протоколу.
Заголовки — це додаткова інформація про запит.
Приклади:
Host — ім’я сервера;
Accept — формати, які клієнт готовий отримати;
Content-Type — формат даних у тілі запиту;
Authorization — дані для автентифікації;
User-Agent — інформація про клієнта;
Content-Length — розмір тіла запиту.
Заголовки мають формат:
Назва: значенняНаприклад:
Accept: application/jsonЦе означає, що клієнт очікує дані у форматі JSON.
Тіло запиту містить дані, які клієнт передає серверу.
Наприклад, під час створення користувача тіло може мати такий вигляд:
{
"name": "Olena",
"email": "olena@example.com"
}Тіло найчастіше використовують із методами POST, PUT і PATCH.
Методи GET зазвичай не використовують для передавання даних у тілі. Для GET параметри частіше додають до URL.
HTTP-метод описує дію, яку клієнт хоче виконати.
GETОтримати ресурс.
GET /usersПриклади:
отримати список користувачів;
отримати одну статтю;
завантажити зображення.
GET не повинен змінювати дані на сервері.
POSTСтворити ресурс або передати дані для обробки.
POST /usersТіло запиту:
{
"name": "Olena"
}PUTПовністю замінити ресурс.
PUT /users/42Зазвичай клієнт передає повний новий стан ресурсу.
PATCHЧастково змінити ресурс.
PATCH /users/42Наприклад, можна передати лише нове ім’я:
{
"name": "Iryna"
}DELETEВидалити ресурс.
DELETE /users/42HTTP-відповідь складається з:
статусного рядка;
заголовків;
порожнього рядка;
необов’язкового тіла.
Приклад:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 36
{"id":42,"name":"Olena"}Статусний рядок містить:
версію HTTP;
числовий код статусу;
текстовий опис статусу.
У прикладі:
HTTP/1.1 200 OKКод 200 означає, що запит виконано успішно.
Сервер використовує заголовки, щоб описати відповідь.
Поширені заголовки:
Content-Type — формат тіла відповіді;
Content-Length — розмір відповіді;
Cache-Control — правила кешування;
Set-Cookie — встановлення cookie;
Location — адреса для перенаправлення;
Access-Control-Allow-Origin — правила доступу з інших джерел.
Тіло відповіді містить результат обробки запиту.
Це може бути:
HTML;
JSON;
текст;
зображення;
відео;
файл;
порожнє тіло.
Приклад JSON-відповіді:
{
"id": 42,
"name": "Olena"
}Коди статусу складаються з трьох цифр. Перша цифра визначає групу.
1xxІнформаційні відповіді. У звичайній розробці клієнт нечасто працює з ними безпосередньо.
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 — ресурс не знайдено;
405 Method Not Allowed — метод не підтримується для цього ресурсу;
409 Conflict — конфлікт даних;
429 Too Many Requests — забагато запитів.
5xxПомилка на стороні сервера.
Поширені коди:
500 Internal Server Error — внутрішня помилка сервера;
502 Bad Gateway — сервер отримав некоректну відповідь від іншого сервера;
503 Service Unavailable — сервіс тимчасово недоступний;
504 Gateway Timeout — інший сервер не відповів вчасно.
Код статусу не завжди означає, що JavaScript викличе помилку. Наприклад, fetch зазвичай успішно повертає об’єкт Response навіть для статусу 404. Статус потрібно перевіряти окремо.
Розглянемо типовий порядок обміну даними.
Наприклад, користувач відкриває сторінку або натискає кнопку «Зберегти».
JavaScript може створити запит так:
fetch("/api/users");Клієнт визначає, до якого сервера належить доменне ім’я.
Для цього використовується DNS — система, яка перетворює доменне ім’я на IP-адресу.
Наприклад:
api.example.com → IP-адреса сервераЗазвичай розробник не виконує цей крок вручну.
Клієнт встановлює мережеве з’єднання із сервером.
Для HTTPS додатково встановлюється захищене TLS-з’єднання. Воно шифрує дані між клієнтом і сервером.
HTTPS захищає дані під час передавання, але не замінює перевірку прав доступу на сервері.
Клієнт надсилає:
метод;
URL;
заголовки;
тіло, якщо воно потрібне.
Наприклад:
GET /api/users HTTP/1.1
Host: example.com
Accept: application/jsonСервер:
приймає запит;
визначає маршрут;
перевіряє метод і дані;
за потреби звертається до бази даних;
виконує бізнес-логіку;
формує відповідь.
Сервер повертає статус, заголовки та тіло:
HTTP/1.1 200 OK
Content-Type: application/json
{"users":[]}Клієнт аналізує відповідь:
перевіряє статус;
читає заголовки;
перетворює тіло в потрібний формат;
показує результат користувачу або виконує іншу логіку.
fetchfetch — стандартний Web API для виконання мережевих запитів.
async function loadUsers() {
const response = await fetch("/api/users");
if (!response.ok) {
throw new Error(`Помилка HTTP: ${response.status}`);
}
const users = await response.json();
console.log(users);
}
loadUsers().catch((error) => {
console.error(error.message);
});Метод response.json() асинхронно читає тіло відповіді та перетворює JSON на JavaScript-значення.
Властивість response.ok має значення true для статусів від 200 до 299.
async function createUser() {
const response = await fetch("/api/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({
name: "Olena",
email: "olena@example.com"
})
});
if (!response.ok) {
throw new Error(`Не вдалося створити користувача: ${response.status}`);
}
const createdUser = await response.json();
console.log("Створено:", createdUser);
}
createUser().catch((error) => {
console.error(error.message);
});Важливі деталі:
method визначає HTTP-метод;
headers описує формат даних;
JSON.stringify перетворює об’єкт JavaScript на JSON-рядок;
response.json() читає JSON-відповідь.
Нижче наведено простий HTTP-сервер і клієнтський запит до нього. Приклад використовує лише вбудований модуль Node.js.
Потрібен Node.js версії 18 або новішої, оскільки в цих версіях доступний глобальний fetch.
const http = require("node:http");
const server = http.createServer((request, response) => {
if (request.method === "GET" && request.url === "/api/message") {
const data = JSON.stringify({
message: "Привіт від сервера!"
});
response.writeHead(200, {
"Content-Type": "application/json; charset=utf-8"
});
response.end(data);
return;
}
response.writeHead(404, {
"Content-Type": "application/json; charset=utf-8"
});
response.end(JSON.stringify({
error: "Маршрут не знайдено"
}));
});
server.listen(3000, async () => {
console.log("Сервер працює на порту 3000");
try {
const response = await fetch("http://localhost:3000/api/message");
const result = await response.json();
console.log("Статус:", response.status);
console.log("Відповідь сервера:", result);
} catch (error) {
console.error("Помилка запиту:", error.message);
} finally {
// Закриваємо сервер після виконання демонстраційного запиту
server.close();
}
});У цьому прикладі:
http.createServer створює сервер;
сервер перевіряє метод і URL;
response.writeHead задає статус і заголовки;
response.end надсилає тіло відповіді;
fetch виконує запит як клієнт;
response.json() читає JSON;
сервер закривається після завершення прикладу.
Запустити файл можна командою:
node server.jsОчікуваний результат:
Сервер працює на порту 3000
Статус: 200
Відповідь сервера: { message: 'Привіт від сервера!' }Мережевий запит займає невизначений час. Сервер може відповісти швидко, повільно або взагалі бути недоступним.
Тому fetch повертає Promise.
Запит можна обробляти за допомогою async/await:
async function loadData() {
try {
const response = await fetch("/api/data");
if (!response.ok) {
throw new Error(`Сервер повернув статус ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error("Не вдалося отримати дані:", error.message);
}
}Блок try...catch обробляє помилки мережі та помилки, які ми створили вручну після перевірки статусу.
Це різні ситуації.
Виникає, коли запит не може нормально дістатися до сервера або відповідь неможливо отримати.
Причини:
сервер вимкнено;
немає мережевого з’єднання;
некоректна адреса;
запит заблоковано політикою браузера.
У такій ситуації fetch зазвичай відхиляє Promise.
Сервер отримав запит і повернув відповідь із кодом, який повідомляє про проблему:
404 Not Found
500 Internal Server ErrorСам факт отримання відповіді не означає, що операція успішна. Тому потрібно перевіряти response.ok або response.status.
JSON часто використовують для обміну даними між JavaScript-клієнтом і сервером.
Правильний запит із JSON має містити:
Content-Type: application/jsonОб’єкт JavaScript перетворюють у JSON так:
const json = JSON.stringify({
name: "Olena"
});JSON-відповідь перетворюють у JavaScript-об’єкт так:
const data = await response.json();Метод response.json() потрібно викликати лише тоді, коли тіло відповіді справді містить JSON.
HTTP не зберігає стан між запитами автоматично.
Наприклад, сервер не обов’язково пам’ятає, що саме цей клієнт робив у попередньому запиті. Щоб зберігати стан користувача, застосовують додаткові механізми:
cookies;
сесії;
токени;
заголовок Authorization;
зовнішнє сховище даних.
Типовий запит із токеном може мати такий заголовок:
Authorization: Bearer token-valueСервер має перевірити цей токен і лише після цього надати доступ до захищеного ресурсу.
Кешування дає змогу повторно використовувати вже отримані дані замість нового завантаження.
На кешування можуть впливати:
заголовок Cache-Control;
заголовок ETag;
заголовок Last-Modified;
налаштування браузера або проміжного сервера.
Кешування пришвидшує роботу, але для даних, які часто змінюються, потрібно правильно визначати час їх актуальності.
Неправильно вважати, що fetch автоматично створить помилку для статусу 404 або 500.
const response = await fetch("/api/users");
const data = await response.json();Краще перевіряти статус:
const response = await fetch("/api/users");
if (!response.ok) {
throw new Error(`HTTP-помилка: ${response.status}`);
}
const data = await response.json();Content-TypeЯкщо клієнт передає JSON, потрібно вказати його формат:
headers: {
"Content-Type": "application/json"
}Без цього сервер може неправильно прочитати тіло запиту.
JSON.stringifyУ fetch тіло JSON-запиту має бути рядком:
body: JSON.stringify({
name: "Olena"
})Передавання звичайного об’єкта замість JSON-рядка не є правильним способом надсилання JSON.
Звичайний HTTP не шифрує трафік. Паролі, токени та інші чутливі дані потрібно передавати через HTTPS.
Метод має відповідати призначенню операції:
GET — отримати;
POST — створити або обробити;
PUT — повністю замінити;
PATCH — частково змінити;
DELETE — видалити.
Клієнтські дані можна змінити вручну. Сервер завжди повинен самостійно:
перевіряти формат даних;
перевіряти права доступу;
перевіряти обмеження;
не довіряти значенням із запиту без валідації.
HTTP — протокол обміну даними між клієнтом і сервером.
Клієнт надсилає запит, а сервер повертає відповідь.
Запит містить метод, URL, заголовки та, за потреби, тіло.
Відповідь містить статус, заголовки та, за потреби, тіло.
Методи GET, POST, PUT, PATCH і DELETE описують основні дії з ресурсами.
Коди 2xx зазвичай означають успіх, 4xx — помилку клієнта, 5xx — помилку сервера.
У JavaScript для запитів часто використовують fetch.
fetch потрібно використовувати разом із перевіркою response.ok або response.status.
Для передавання JSON потрібно вказувати Content-Type: application/json і використовувати JSON.stringify.
HTTPS шифрує обмін даними між клієнтом і сервером.