Пошук уроків, статей та іншого контенту
Розглянемо модель HTTP, учасників обміну, структуру повідомлень і життєвий цикл запиту та відповіді.
HTTP (HyperText Transfer Protocol) — протокол, за допомогою якого програми обмінюються повідомленнями в мережі.
Найчастіше HTTP використовують для обміну між:
браузером і вебсервером;
мобільним застосунком і сервером;
одним сервером та іншим сервером;
клієнтом і API.
HTTP визначає:
як клієнт формує запит;
як сервер формує відповідь;
які методи та статуси можна використовувати;
як передавати заголовки й тіло повідомлення.
HTTP не визначає, як саме сервер зберігає дані або як побудована його бізнес-логіка. Він описує лише формат і правила обміну повідомленнями.
Клієнт — програма, яка ініціює HTTP-запит.
Клієнтами можуть бути:
браузер;
Node.js-програма;
мобільний застосунок;
утиліта командного рядка;
інший сервер.
Клієнт повідомляє серверу, який ресурс йому потрібен і яку дію треба виконати.
Сервер — програма, яка приймає запити та формує відповіді.
Наприклад, сервер може:
повернути HTML-сторінку;
віддати дані у форматі JSON;
створити нового користувача;
перевірити облікові дані;
повідомити про помилку.
Один сервер може обробляти запити від багатьох клієнтів.
Між клієнтом і сервером можуть працювати додаткові компоненти:
проксі-сервер;
балансувальник навантаження;
кеш;
шлюз API.
Для базової моделі достатньо пам’ятати головне:
Клієнт надсилає запит, сервер повертає відповідь.
HTTP-обмін складається з двох основних повідомлень:
HTTP-запит — повідомлення від клієнта до сервера.
HTTP-відповідь — повідомлення від сервера до клієнта.
Наприклад, клієнт хоче отримати список товарів:
GET /products HTTP/1.1
Host: example.com
Accept: application/jsonСервер може відповісти так:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 27
{"items":["book","laptop"]}У кожного повідомлення є:
стартовий рядок;
заголовки;
порожній рядок між заголовками й тілом;
необов’язкове тіло.
У сучасних версіях HTTP внутрішній формат передавання може відрізнятися, але поняття запиту, відповіді, заголовків і тіла залишаються важливими.
HTTP-запит має таку загальну структуру:
METHOD /path HTTP/version
Header-Name: value
Another-Header: value
bodyМетод описує бажану дію над ресурсом.
Найпоширеніші методи:
GET — отримати дані;
POST — надіслати дані або створити ресурс;
PUT — повністю оновити ресурс;
PATCH — частково оновити ресурс;
DELETE — видалити ресурс.
Наприклад:
GET /usersозначає запит на отримання ресурсу /users.
А запит:
DELETE /users/42означає бажання видалити користувача з ідентифікатором 42.
Шлях вказує, з яким ресурсом працює клієнт.
/products
/products/15
/users/42/ordersУ повному URL шлях є частиною адреси:
https://example.com/products/15Тут:
https — схема;
example.com — домен;
/products/15 — шлях.
До шляху можна додати параметри після символу ?:
/products?category=books&page=2У цьому прикладі:
category має значення books;
page має значення 2.
Параметри рядка запиту часто використовують для:
фільтрації;
сортування;
пошуку;
пагінації.
Заголовки — це пари «ім’я — значення», які передають додаткову інформацію.
Приклади заголовків запиту:
Host: example.com
Accept: application/json
Content-Type: application/json
Authorization: Bearer tokenЗаголовок Accept повідомляє, який формат відповіді бажає отримати клієнт.
Заголовок Content-Type описує формат даних у тілі запиту.
Наприклад:
Content-Type: application/jsonозначає, що тіло запиту містить JSON.
Тіло містить дані, які клієнт передає серверу. Воно найчастіше використовується з методами POST, PUT і PATCH.
Приклад запиту з JSON-тілом:
POST /users HTTP/1.1
Host: example.com
Content-Type: application/json
{"name":"Olena","email":"olena@example.com"}Тіло запиту не є обов’язковим. Наприклад, звичайний GET часто не має тіла.
HTTP-відповідь має таку загальну структуру:
HTTP/version status-code reason-phrase
Header-Name: value
bodyСтатус-код повідомляє, чим завершилася обробка запиту.
Статус-коди поділяють на групи:
1xx — інформаційні повідомлення;
2xx — запит успішно виконано;
3xx — перенаправлення;
4xx — помилка на стороні клієнта;
5xx — помилка на стороні сервера.
Найпоширеніші коди:
200 OK — запит успішно виконано;
201 Created — ресурс створено;
204 No Content — запит успішний, але тіло відповіді відсутнє;
400 Bad Request — некоректний запит;
401 Unauthorized — потрібна автентифікація;
403 Forbidden — доступ заборонено;
404 Not Found — ресурс не знайдено;
500 Internal Server Error — внутрішня помилка сервера.
Наприклад:
HTTP/1.1 404 Not Foundозначає, що сервер не знайшов запитаний ресурс.
Заголовки відповіді описують результат і дані, які повертає сервер:
Content-Type: application/json
Content-Length: 27
Cache-Control: no-cacheЗаголовок Content-Type вказує формат тіла відповіді.
Поширені значення:
text/html
application/json
text/plain
image/pngТіло містить дані, які сервер повертає клієнту.
Наприклад, відповідь API може містити JSON:
{
"id": 42,
"name": "Olena"
}HTML-сторінка також є тілом HTTP-відповіді:
<h1>Головна сторінка</h1>Відповідь може не мати тіла. Наприклад, сервер може повернути статус 204 No Content.
Node.js має вбудований модуль http, за допомогою якого можна створити HTTP-сервер без встановлення додаткових пакетів.
Створимо сервер із двома маршрутами:
GET / повертає текст;
GET /api/message повертає JSON;
для інших шляхів сервер повертає 404.
const http = require('node:http');
const server = http.createServer((request, response) => {
// Виводимо метод і шлях запиту в консоль
console.log(`${request.method} ${request.url}`);
if (request.method === 'GET' && request.url === '/') {
response.writeHead(200, {
'Content-Type': 'text/plain; charset=utf-8'
});
response.end('Вітаємо на HTTP-сервері!');
return;
}
if (request.method === 'GET' && request.url === '/api/message') {
const data = {
message: 'HTTP працює',
source: 'Node.js'
};
response.writeHead(200, {
'Content-Type': 'application/json; charset=utf-8'
});
response.end(JSON.stringify(data));
return;
}
response.writeHead(404, {
'Content-Type': 'text/plain; charset=utf-8'
});
response.end('Ресурс не знайдено');
});
server.listen(3000, () => {
console.log('Сервер запущено на http://localhost:3000');
});Збережіть код у файлі server.js і запустіть:
node server.jsПісля цього можна виконати запити:
curl http://localhost:3000/Результат:
Вітаємо на HTTP-сервері!Запит до API:
curl http://localhost:3000/api/messageРезультат:
{"message":"HTTP працює","source":"Node.js"}Запит до невідомого шляху:
curl http://localhost:3000/unknownРезультат:
Ресурс не знайденоУ прикладі:
request.method містить HTTP-метод;
request.url містить шлях запиту;
response.writeHead() задає статус і заголовки;
response.end() завершує відповідь і може передати її тіло.
Розглянемо послідовність обміну для запиту GET /api/message.
Клієнт визначає:
адресу сервера;
HTTP-метод;
шлях;
заголовки;
за потреби — тіло.
Наприклад:
GET /api/message HTTP/1.1
Host: localhost:3000
Accept: application/jsonЗапит надходить на адресу та порт, де сервер очікує з’єднання.
У нашому прикладі Node.js-сервер слухає порт 3000:
server.listen(3000);Сервер читає:
метод;
URL;
заголовки;
тіло, якщо воно є.
Потім він вирішує, яку логіку виконати. У прикладі сервер перевіряє метод і шлях:
request.method === 'GET' && request.url === '/api/message'Залежно від запиту сервер може:
знайти дані;
перевірити права доступу;
обробити передане тіло;
сформувати результат.
У навчальному прикладі сервер просто створює об’єкт із повідомленням.
Сервер задає:
статус-код;
заголовки;
тіло відповіді.
response.writeHead(200, {
'Content-Type': 'application/json; charset=utf-8'
});
response.end(JSON.stringify(data));Клієнт перевіряє статус і читає дані.
Наприклад:
браузер показує HTML;
JavaScript перетворює JSON на об’єкт;
мобільний застосунок показує повідомлення;
інший сервер використовує дані у своїй логіці.
HTTP за базовою моделлю є stateless, тобто сервер не зобов’язаний пам’ятати попередній запит клієнта.
Два запити обробляються незалежно:
GET /profile
GET /profileСам факт, що клієнт уже надсилав перший запит, не означає, що сервер автоматично знає про це під час другого запиту.
Якщо потрібно передати додатковий контекст, клієнт додає його до запиту, наприклад через:
заголовки;
cookies;
параметри;
тіло запиту.
На рівні базового HTTP важливо запам’ятати:
Кожен запит має містити достатньо інформації, щоб сервер міг його обробити.
HTTP і HTTPS використовують однакову базову модель запитів і відповідей.
Відмінність полягає в захисті передавання:
HTTP передає дані без шифрування на рівні протоколу;
HTTPS використовує шифроване з’єднання.
Під час роботи з реальними сервісами зазвичай використовують HTTPS, особливо коли передаються паролі, токени або персональні дані.
У цьому запиті:
GET /usersGET — це метод, а /users — шлях.
Це різні частини запиту, і сервер може по-різному обробляти однаковий шлях із різними методами.
Тіло відповіді саме по собі не показує, чи був запит успішним.
Наприклад, сервер може повернути текст помилки разом зі статусом 404. Клієнт має перевіряти і статус-код, і тіло відповіді.
Content-TypeЯкщо тіло містить JSON, серверу потрібно повідомити про це:
Content-Type: application/jsonБез цього сервер може неправильно інтерпретувати передані дані.
У Node.js відповідь потрібно завершити за допомогою response.end().
Якщо цього не зробити, клієнт може чекати завершення запиту безкінечно.
Тіло запиту є необов’язковим. Звичайний GET часто передає параметри через шлях або рядок запиту, а не через тіло.
HTTP — протокол обміну повідомленнями між клієнтом і сервером.
Клієнт надсилає запит, сервер повертає відповідь.
Запит містить метод, шлях, заголовки й необов’язкове тіло.
Відповідь містить статус-код, заголовки й необов’язкове тіло.
Метод описує дію: отримати, створити, оновити або видалити дані.
Статус-код показує результат обробки запиту.
Content-Type описує формат тіла повідомлення.
Node.js може створювати HTTP-сервери за допомогою вбудованого модуля node:http.
HTTP є протоколом без стану: кожен запит обробляється як окреме повідомлення.