У світі веб-розробки термін "middleware" (проміжне програмне забезпечення) може здаватися фоновим шумом, але насправді це основа добре структурованої програми. Функції middleware є необхідними складовими, які підтримують плавну роботу складних додатків, організовуючи та керуючи завданнями в циклі запит-відповідь.
Middleware існує на різних рівнях — від низькорівневого, системного middleware (як драйвери мережі та сервіси операційної системи) до middleware на рівні додатків, на якому ми зосередимося тут. Middleware рівня додатка працює в межах веб-фреймворку для обробки специфічних завдань, поки кожен HTTP-запит проходить через додаток.
Можливо, ви запитаєте, Що робить middleware таким важливим? Middleware спрощує обробку перехресних питань, таких як автентифікація, логування та керування помилками, не перевантажуючи логіку маршрутів. У цій статті ми розглянемо, як працює middleware на рівні додатка в таких фреймворках, як Node.js Express, .NET та Go Fiber. Ми побачимо, як кожен фреймворк обробляє middleware, яку роль відіграє функція next
в управлінні потоком запитів, а також як middleware формує досвід користувача у вашому веб-додатку.
Що таке Middleware?
По суті, middleware — це функція або послідовність функцій, які обробляють запити та відповіді у веб-додатку. Але middleware не лише стосується обробки запитів — він визначає, як ці запити обробляються. Він може модифікувати запит до того, як він потрапить до основного обробника, або змінювати відповідь перед тим, як вона буде відправлена назад клієнту.
Простіше кажучи, middleware діє як проміжний шар, який дозволяє вам обробляти, перевіряти або відхиляти HTTP-запити на різних етапах. Це дозволяє вам:
- Автентифікація/Авторизація: Перевіряє, чи дозволено користувачу отримати доступ до ресурсу.
- Логування: Відслідковує деталі запиту, такі як IP-адреса, час запиту та дії користувача для моніторингу та налагодження.
- Обробка помилок: Ловить помилки в централізованій точці, забезпечуючи узгоджені відповіді для всіх маршрутів.
- Стиснення: Стискає відповіді для зменшення обсягу переданих даних, покращуючи час завантаження.
- Обмеження запитів: Обмежує кількість запитів від одного користувача, щоб запобігти зловживанню.
- Кешування: Тимчасово зберігає відповіді, щоб часто запитувані дані можна було отримати швидше.
- Валідація запитів: Перевіряє, чи відповідають вхідні запити конкретним вимогам, таким як правильні формати даних чи обов'язкові поля.
Уявіть middleware як контрольно-пропускний пункт в аеропорту. Кожен запит (або пасажир) проходить через кілька перевірок — автентифікація, валідація, логування — перед тим, як потрапити до фінальних воріт (обробника маршруту).
Порядок важливий: важливість послідовності Middleware
Один з критичних аспектів middleware полягає в тому, що порядок має значення. Послідовність, в якій реєструються функції middleware, впливає на те, як обробляються запити. Функції middleware виконуються в порядку їх реєстрації, що означає, що неправильний порядок може порушити потік додатка або навіть зламати функціональність.
Наприклад, уявіть, що ви маєте обмеження запитів на основі користувачів:
app.use(logRequest); // Логує деталі запиту
app.use(authenticateUser); // Автентифікує користувача
app.use(rateLimit); // Обмежує кількість запитів від користувача
У цьому порядку кожен запит спочатку логуватиметься, потім перевірятиметься на автентифікацію, а потім обмежуватиметься за швидкістю перед тим, як дійти до обробника. Однак, якщо ми помилково поміняємо місцями автентифікацію і обмеження швидкості:
app.use(logRequest); // Логує деталі запиту
app.use(rateLimit); // Обмежує кількість запитів від користувача
app.use(authenticateUser); // Автентифікує користувача
Якщо ми використовуємо таку облікову інформацію, як userId
, це не спрацює, оскільки інформація про користувача, яку нам потрібно, ще не зареєстрована.
Якщо ми використовуємо цей ввід, middleware буде застосовуватися до всіх запитів, навіть до неавтентифікованих, що потенційно заблокує доступ до того, як перевірено облікові дані користувача. Це може призвести до фрустрації користувача та витрати ресурсів, якщо неавтентифіковані запити будуть обмежені за кількістю.
Забезпечення правильного порядку для кожного шару middleware є ключем до побудови плавного, безпечного та надійного конвеєра.
Функція "Next"
Один з найважливіших аспектів розуміння middleware — це концепція функції next
. Якщо ви працювали з middleware раніше, ви, ймовірно, бачили таке:
app.use((req, res, next) => {
console.log("Middleware 1");
next(); // Перехід до наступного middleware
});
Але що робить next()
?
Коли запит потрапляє на веб-сервер, він не просто прямує безпосередньо до обробника маршруту. Замість цього він проходить через серію функцій middleware. Коли ви викликаєте next()
, ви кажете: "Добре, цей middleware виконав свою роботу — передати запит до наступної функції в черзі."
Коротко кажучи, middleware втручається в потік запит-відповідь, а функція next()
гарантує, що потік продовжиться.
Middleware в дії
Тепер давайте розглянемо, як працює middleware в трьох популярних веб-фреймворках: Node.js Express, ASP.NET та Go Fiber. Кожен з цих фреймворків використовує middleware, але їх реалізація виглядає трохи по-різному.
Middleware в Express
У express middleware є всюди. Ось базовий приклад:
const express = require('express');
const compression = require('compression')
const app = express();
// Стандартний Middleware, який стискає кожну відповідь
app.use(compression())
// Користувацький Middleware, який логуватиме кожен запит
app.use((req, res, next) => {
const start = Date.now();
next(); // Викликаємо наступний middleware або обробник маршруту
const duration = Date.now() - start;
console.log(`Запит до ${req.path} зайняв ${duration}мс`);
});
// Обробник маршруту
app.get('/home', (req, res) => {
res.send('Ласкаво просимо на домашню сторінку');
});
app.listen(3000);
Middleware в .NET
У .NET middleware використовується подібним чином, хоча синтаксис і налаштування трохи відрізняються.
Ось приклад того, як це працює в додатку ASP.NET Core:
using Microsoft.AspNetCore.Builder;
var builder = WebApplication.CreateBuilder(args);
// Включення стиснення відповіді з налаштуваннями за замовчуванням
builder.Services.AddResponseCompression();
var app = builder.Build();
// Стандартний Middleware, що стискає кожну відповідь
app.UseResponseCompression();
// Користувацький Middleware, що логуватиме кожен запит
app.Use(async (context, next) =>
{
var start = DateTime.Now;
await next(); // Передаємо контроль до наступного middleware або обробника маршруту
var duration = DateTime.Now - start;
Console.WriteLine($"Запит до {context.Request.Path} зайняв {duration.TotalMilliseconds}мс");
});
// Обробник маршруту
app.MapGet("/home", () => "Ласкаво просимо на домашню сторінку");
// Запуск додатку
app.Run();
Middleware в Go Fiber
Тепер давайте перейдемо до Go Fiber, веб-фреймворку, побудованого на основі Fasthttp, який забезпечує продуктивність, подібну до Express, але з ароматом Go.
Ось приклад:
package main
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/compress"
"log"
"time"
)
func main() {
app := fiber.New()
// Стандартний Middleware, що стискає кожну відповідь
app.Use(compress.New())
// Користувацький Middleware, що логуватиме кожен запит
app.Use(func(c *fiber.Ctx) error {
start := time.Now()
err := c.Next() // Передаємо контроль до наступного middleware або обробника маршруту
duration := time.Since(start)
log.Printf("Запит до %s зайняв %v", c.Path(), duration)
return err
})
// Обробник маршруту
app.Get("/home", func(c *fiber.Ctx) error {
return c.SendString("Ласкаво просимо на домашню сторінку")
})
// Запуск сервера на порту 3000
log.Fatal(app.Listen(":3000"))
}
Висновок
Підсумовуючи, middleware — це зручний спосіб обробляти кросс-функціональні задачі, такі як логування, стиснення та автентифікацію у веб-додатках. Незалежно від того, чи використовуєте ви Node.js, .NET чи Go, middleware допомагає ефективно організувати ці задачі. Розуміння того, як працювати з функцією next та порядком middleware, дозволяє зберігати код чистим і адаптивним, полегшуючи побудову масштабованих додатків, які добре реагують на зміни в потребах.
Перекладено з: What is Middleware?