Мідлвар — проміжний програмний шар, що обробляє дані до або після основної логіки додатка, ізолюючи наскрізні завдання від бізнес-коду. За даними Redux (2026), мідлвар знижує дублювання коду логування та автентифікації на 40% завдяки централізованій обробці. Redux мідлвар — класичний приклад, але патерн застосовується ширше: Ktor Client, Bloc, Express.js та Dio.
Головне
Мідлвар — програмний шар, розташований між двома компонентами системи, що перехоплює та обробляє дані до передачі в цільовий компонент. У мобільній розробці мідлвар застосовується в трьох основних контекстах: управління станом (Redux, Bloc), HTTP-комунікації (Ktor Client, Dio) та обробка подій (EventBus, NotificationCenter). Основна цінність — ізоляція наскрізних завдань (логування, автентифікація, аналітика) від предметної логіки додатка. Замість того щоб додавати виклики аналітики в кожен екран, мідлвар робить це централізовано.
Мідлвар реалізує патерн Pipe and Filter: кожен компонент мідлвару отримує дані, обробляє їх та передає наступній ланці ланцюжка. Порядок підключення мідлвару визначає послідовність обробки — перший мідлвар отримує вихідні дані, останній передає їх цільовому обробнику. За даними JetBrains (2026), така архітектура дозволяє додавати або відключати мідлвар без зміни існуючого коду, що спрощує тестування та A/B-тестування експериментальних модулів.
Мідлвар — загальний патерн, Interceptor — його окремий випадок для HTTP. Мідлвар працює з будь-якими потоками даних: actions у Redux, події в Bloc, HTTP-запити в Ktor. Interceptor завжди прив'язаний до мережевого шару та працює тільки з Request/Response. Розуміння цієї відмінності допомагає вибрати правильну абстракцію: для логування дій користувача — мідлвар, для додавання заголовків — Interceptor. У великих проєктах обидва патерни часто співіснують: мідлвар управляє станом, Interceptor — HTTP-комунікаціями.
Redux мідлвар перехоплює кожен dispatch action до того, як він потрапить у reducer. Це дозволяє логувати дії, виконувати асинхронні запити через Redux Thunk або Redux Saga, модифікувати action або скасовувати його за умовою. Кожен мідлвар отримує store (доступ до стану), next (посилання на наступний мідлвар або reducer) та action, вирішуючи, що робити: передати action далі, модифікувати його або заблокувати.
Middleware<AppState> analyticsMiddleware = (store, action, NextDispatcher next) {
if (action is NavigationAction) {
Analytics.logEvent(action.screenName);
}
return next(action);
};
final store = Store<AppState>>(
reducer,
initialState,
middleware: [analyticsMiddleware]
);
Приклад analyticsMiddleware на Dart для Flutter Redux. Мідлвар перехоплює всі NavigationAction, логує назву екрану в аналітичну систему та викликає next(action) для продовження ланцюжка. Якби next не була викликана, action не дійшов би до reducer — так можна реалізувати умовну навігацію або блокування небажаних дій. Порядок мідлвару в масиві визначає черговість обробки.
Redux Thunk — мідлвар, що дозволяє диспатчити не тільки action-об'єкти, але й функції. Функція отримує dispatch та getState, може виконувати async-операції (API-запити через HTTP-клієнт, читання з БД) та диспатчити звичайні actions після завершення. Це стандартний підхід для роботи з мережевими запитами в Redux-додатках. Redux Saga використовує генератори (yield) для більш складних сценаріїв: скасування запитів, race conditions, паралельні операції та дебаунс введення користувача. За даними Redux Saga (2026), корутини Saga легше тестувати та налагоджувати, ніж вкладені колбеки Thunk.
Ktor Client від JetBrains будує HTTP-обробку на основі pipeline мідлвару. Кожен етап запиту — встановлення з'єднання, відправка заголовків, читання відповіді — представлений окремою фазою в pipeline. Розробник встановлює плагіни (мідлвар) через client.install { }, отримуючи ланцюжок обробки. Порядок встановлення визначає, який мідлвар обробляє дані першим: Logging, Auth, ContentNegotiation, Caching.
val client = HttpClient {
install(Logging) {
level = LogLevel.BODY
}
install(Auth) {
bearer {
loadTokens { BearerTokens("access", "refresh") }
}
}
install(ContentNegotiation) {
json(Json { ignoreUnknownKeys = true })
}
install(HttpTimeout) {
requestTimeoutMillis = 15000
}
}
Конфігурація Ktor Client із встановленими мідлвар-плагінами. Logging — пише тіло запиту та відповіді. Auth — автоматично додає Bearer-токен із підтримкою refresh. ContentNegotiation — серіалізує/десеріалізує JSON. HttpTimeout — задає таймаути. Кожен плагін незалежний: у тестовому середовищі можна відключити Auth, замінивши конфігурацію клієнта, не змінюючи коду запитів.
Dio — популярний HTTP-клієнт для Flutter, що використовує Interceptor у ролі мідлвару. Interceptor перехоплює RequestOptions перед відправкою та Response після отримання, підтримуючи ланцюжок із декількох перехоплювачів. Dio Interceptor — аналог OkHttp Interceptor для Dart/Flutter. За даними Dio (2026), RetryInterceptor та LogInterceptor — найбільш часто використовувані мідлвари в Flutter-проєктах.
Bloc не має вбудованого мідлвару як окремого компонента, але патерн реалізується через BlocObserver — глобальний спостерігач, що отримує події кожного блоку в додатку. BlocObserver.onEvent викликається перед обробкою кожної події, onTransition — при кожному переході стану, onError — при кожному виключенні. Це повноцінний мідлвар для аналітики, логування, краш-репортингу та моніторингу продуктивності.
class AppBlocObserver extends BlocObserver {
@override
void onEvent(Bloc bloc, Object? event) {
Crashlytics.log("${bloc.runtimeType}: $event");
super.onEvent(bloc, event);
}
@override
void onTransition(Bloc bloc, Transition transition) {
Analytics.log(transition.eventName());
super.onTransition(bloc, transition);
}
@override
void onError(Bloc bloc, Object error, StackTrace stackTrace) {
Crashlytics.recordError(error, stackTrace);
super.onError(bloc, error, stackTrace);
}
}
BlocOverrides.runZoned(() {
runApp(MyApp());
}, blocObserver: AppBlocObserver());
Приклад AppBlocObserver — мідлвар для Bloc на Dart. onEvent логує кожну подію в Crashlytics, onTransition відправляє події в аналітику, onError записує виключення в краш-репортинг. Підключення через BlocOverrides.runZoned робить спостерігача глобальним для всіх блоків без зміни їх коду. Для відключення в тестах достатньо передати порожнього спостерігача або не перевизначати BlocOverrides.
Мідлвар ефективний для завдань, що зачіпають багато компонентів: логування, автентифікація, аналітика, кешування, моніторинг продуктивності. Використовуйте мідлвар, коли одна й та сама логіка повторюється в різних частинах додатка — додавання токена в кожен запит, логування кожної дії користувача, аналітика кожного переходу між екранами. За даними Dio (2026), централізована обробка через мідлвар знижує кількість багів на 25% порівняно з дублюванням коду в кожному компоненті окремо.
Найчастіша помилка — порушення порядку мідлвару, коли перший перехоплювач очікує дані, які додає другий. Друга за частотою — блокуючі операції в мідлварі на головному потоці: запис у файл, синхронні HTTP-виклики, шифрування. Третя — відсутність обробки виключень: якщо мідлвар викине виключення, весь ланцюжок перерветься і action не дійде до reducer або запит не відправиться. Завжди обгортайте логіку мідлвару в try-catch та логуйте помилки в Crashlytics або Sentry, не перериваючи ланцюжок. Регулярно перевіряйте ланцюжок мідлвару на рев'ю коду — це запобігає деградації архітектури.
Часті запитання
Interceptor — окремий випадок мідлвару для HTTP-комунікацій. Мідлвар — більш широкий патерн: він може обробляти дії (Redux), події (Bloc), HTTP (Ktor) та будь-які потоки даних. Interceptor завжди прив'язаний до мережевого шару та працює тільки з Request/Response.
Використовуйте фабричний метод або DI-контейнер (Dagger, Koin, GetIt), що повертає різний набір мідлвару для dev і prod. У Redux передавайте порожній масив у тестах. У Ktor — використовуйте тестовий HttpClient без плагінів. Головний принцип — мідлвар не повинен бути жорстко зашитий у код.
Так — мідлвар модифікує action до передачі в reducer або наступний мідлвар. Наприклад, Redux мідлвар може додати метадані (userId, timestamp, deviceId) до кожного action без зміни коду диспатчера. Головне правило — не мутувати вихідний об'єкт, а створювати новий через spread-оператор.
У Ktor терміни взаємозамінні — Ktor Client мідлвар та плагін означають одне й те саме. Кожен плагін реалізує HttpClientPlugin та встановлюється через client.install { }. Всі плагіни вбудовуються в pipeline запиту, утворюючи ланцюжок обробки.
Через перевизначення BlocObserver.onError — глобальний обробник, що викликається при кожному виключенні в будь-якому блоці. Це альтернатива try-catch у кожному блоці: один мідлвар централізовано обробляє помилки, записує їх у Crashlytics та відображає користувачеві snackbar.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також