Модуль 18

Middleware: що це і навіщо

Ось готовий урок, створений за твоїм майстер-промптом.


🎓 CS50-Style Lesson: Middleware (Прошарок)

Привіт, друзі! Мене звати [Твоє Ім'я], і це... ні, не Гарвард, але ми тут, щоб розібратися з однією з найважливіших концепцій у веб-розробці.

Сьогодні ми говоримо про Middleware.

Звучить як щось складне й абстрактне, правда? Але я обіцяю: до кінця цього уроку ви не просто зрозумієте, що це таке, а й будете дивуватися, як ви взагалі писали код без нього.


1. 🔥 Вступ: Проблема та мотивація

Уявіть, що ви власник елітного нічного клубу. У вас є бармен, ді-джей і VIP-зона.

Тепер уявіть ситуацію: до бармена підходить людина і просить коктейль. Бармен, замість того щоб просто налити напій, мусить спочатку запитати: "А тобі є 18 років?", перевірити паспорт, потім перевірити, чи є людина в списку гостей, і тільки потім налити.

Потім ця ж людина йде до VIP-зони. Охоронець VIP-зони знову перевіряє паспорт, знову шукає в списку...

Питання до вас: Чи ефективно це? Чи повинен бармен займатися перевіркою паспортів?

Звісно, ні! Бармен має наливати, ді-джей — грати музику.

У програмуванні те саме. Уявіть, що у вас є 50 маршрутів (сторінок) на сайті. * Ви хочете, щоб доступ до них мали лише зареєстровані користувачі. * Ви хочете записувати в лог кожен запит, щоб знати, хто прийшов.

Невже ви будете копіювати код перевірки користувача (if user.is_logged_in) у кожну з цих 50 функцій?

Проблема: Дублювання коду, хаос, і якщо логіка зміниться — доведеться правити в 50 місцях. Рішення: Поставити на вході "фейс-контроль". Оце і є Middleware.


2. 🧠 Теоретична база (Як це працює "під капотом")

Давайте розберемо це поняття без зайвих академізмів.

Middleware (мідлвар, проміжне ПЗ) — це функція (або шматок коду), яка виконується між отриманням запиту від клієнта (Request) і відправкою фінальної відповіді (Response).

Уявіть собі конвеєр на заводі. 1. Сировина (Запит) заїжджає на стрічку. 2. Middleware 1: Миє сировину. 3. Middleware 2: Фарбує сировину. 4. Middleware 3: Перевіряє якість. 5. Фінальний обробник: Пакує і віддає клієнту.

Як це виглядає в коді (логіка):

Кожна функція Middleware має доступ до трьох речей: 1. 📦 Request (req) — що нам прислали. 2. 📝 Response (res) — що ми віддамо. 3. ➡️ Next — чарівна кнопка "передати далі".

❗️ Що треба запам’ятати залізно: Middleware має лише два шляхи: 1. Або передати естафету далі, викликавши next(). 2. Або перервати ланцюжок і віддати відповідь одразу (наприклад, "Помилка: Доступ заборонено").

Якщо Middleware не зробить ні того, ні іншого — ваш сайт "зависне", клієнт буде вічно чекати відповіді.


3. 🧪 Приклади (Step-by-Step)

Для прикладів використаємо синтаксис JavaScript (Node.js/Express), бо він тут найчитабельніший, але логіка ідентична в Python (Django/FastAPI), Go чи PHP.

Приклад 1: "Балакучий спостерігач" (Logging)

Найпростіший приклад. Ми хочемо просто знати, що хтось зайшов на сайт.

// Це наш Middleware
function logger(req, res, next) {
    console.log("Хтось постукав у двері!");
    next(); // 👈 Ключовий момент! Передаємо управління далі.
}

// Використовуємо його
app.use(logger);

// Наш головний маршрут
app.get('/', (req, res) => {
    res.send("Привіт, це головна сторінка!");
});

Питання до студента: Що буде, якщо я видалю рядок next() у функції logger, а потім спробую зайти на сайт? (Подумай секунду...) Відповідь: Браузер буде крутити значок завантаження вічно. Сервер прийняв запит, вивів повідомлення в консоль, але не знає, що робити далі. Ланцюжок розірвано.


Приклад 2: "Суворий охоронець" (Authentication)

Тепер реальний кейс. Захищаємо секретну сторінку.

function checkPassword(req, res, next) {
    // Уявимо, що пароль передали в запиті
    if (req.query.password === "secret123") {
        next(); // Пароль вірний? Проходь!
    } else {
        res.send("🛑 Стояти! Пароль невірний."); // Перериваємо ланцюжок!
    }
}

// Застосовуємо ТІЛЬКИ до секретної сторінки
app.get('/secret', checkPassword, (req, res) => {
    res.send("💰 Ось наші скарби!");
});

Чому це круто? Функція app.get (наш фінальний обробник) навіть не знає про існування паролів. Вона просто віддає скарби. Вона впевнена: якщо управління дійшло до неї, значить, охоронець уже все перевірив. Це називається Clean Code.


Приклад 3: "Дбайливий асистент" (Data Processing)

Middleware може не тільки пропускати або забороняти, а й щось додавати до запиту.

function addTimestamp(req, res, next) {
    // Додаємо нову властивість до об'єкта запиту
    req.requestTime = new Date().toString();
    next();
}

app.use(addTimestamp);

app.get('/', (req, res) => {
    // Тепер ми можемо використовувати req.requestTime!
    res.send("Ви зайшли о: " + req.requestTime);
});

Тут Middleware діє як асистент, який підготував документи для шефа (додав час), щоб шефу (контролеру) не треба було дивитися на годинник.


4. 🛠 Практична частина

Час забруднити руки кодом (або псевдокодом).

Завдання 1. Повторення Напиши middleware, який просто виводить у консоль метод запиту (GET, POST) і URL. (Підказка: в req зазвичай є поля req.method та req.url).

Завдання 2. Режим "Технічні роботи" Уяви, що сайт зламався. Напиши middleware, який стоїть найпершим і на будь-який запит відповідає: "Вибачте, ми зачинені на ремонт". (Важливо: чи потрібен тут next()?)

Завдання 3. Виправляємо помилку новачка Студент написав код:

function myMiddleware(req, res, next) {
    if (req.url === '/admin') {
        res.send("Тут тільки для адмінів");
    }
    next();
}

Питання: Що станеться, якщо юзер зайде на /admin? (Підказка: помилка "Headers already sent" або креш сервера. Чому ми викликаємо next() після відправки відповіді?)

Завдання 4. Кейс "Фейс-контроль 18+" Напиши middleware, який перевіряє вік користувача (умовно req.age). * Якщо < 18 — відправ помилку "Тобі сюди не можна". * Якщо >= 18 — пропусти далі.

Завдання 5. Міні-кейс (на подумати) Тобі треба зробити так, щоб користувач не міг надсилати більше 5 запитів за хвилину (захист від спаму). Опиши словесно логіку такого middleware. Де б ти зберігав лічильник запитів?


5. 💡 Мислення як у розробника

Як відрізнити новачка від профі в темі Middleware?

1. Порядок має значення! Новачки часто плутають порядок підключення. * Якщо ви поставите middleware ErrorHandler (обробка помилок) на самому початку — він нічого не зловить. * Якщо ви поставите перевірку пароля після того, як віддали дані — це дірка в безпеці.

Порада: Уявляйте код як фізичний тунель. Хто стоїть першим біля входу?

2. "Товсті" контролери — це погано. Якщо ви бачите у своїй фінальній функції (контролері) 50 рядків коду, де ви перевіряєте валідацію пошти, права доступу, форматуєте дату... ЗУПИНІТЬСЯ. Винесіть це в middleware. Контролер має бути "тупим": взяв підготовлені дані -> віддав відповідь.

3. Не забувайте про return Коли ви робите res.send("Error"), код не зупиняється автоматично! Функція продовжує виконуватися далі. * Bad: if (error) res.send("Error"); next(); (Буде баг!) * Good: if (error) return res.send("Error");


6. 🧩 Підсумок

Отже, що ми сьогодні розібрали?

  1. Middleware — це посередник. Він стоїть між клієнтом і сервером.
  2. Він може: виконати код, змінити запит/відповідь, завершити запит або викликати наступного.
  3. Без нього ваш код перетвориться на спагеті з однакових перевірок.

Що ти тепер вмієш? Ти можеш "перехоплювати" запити. Ти розумієш, як працюють плагіни авторизації, логування та обробки помилок у будь-якому сучасному фреймворку.

🔮 Тизер наступного уроку: Ми навчилися перевіряти, хто прийшов. Але як сервер запам'ятовує користувача між запитами, щоб не питати пароль щоразу? На наступному уроці розберемо Sessions, Cookies та JWT. Готуйтеся, будемо печиво їсти (або ні).

А тепер — йдіть і напишіть свій перший "фейс-контроль"! 🚀