Middleware — междинен софтуерен слой, който обработва данни преди или след основната логика на приложението, изолирайки общи задачи от бизнес кода. Според данни на Redux (2026), middleware намалява дублирането на код за логване и удостоверяване с 40% благодарение на централизираната обработка. Redux middleware — класически пример, но моделът се прилага по-широко: Ktor Client, Bloc, Express.js и Dio.
Основни точки
Middleware — софтуерен слой, разположен между два компонента на системата, който прихваща и обработва данни преди предаването им към целевия компонент. В мобилната разработка middleware се прилага в три основни контекста: управление на състоянието (Redux, Bloc), HTTP комуникация (Ktor Client, Dio) и обработка на събития (EventBus, NotificationCenter). Основната стойност — изолиране на общи задачи (логване, удостоверяване, аналитика) от бизнес логиката на приложението. Вместо да добавяте извикване на аналитика към всеки екран, middleware прави това централизирано.
Middleware имплементира модела Pipe and Filter: всеки middleware компонент получава данни, обработва ги и ги предава на следващото звено от веригата. Редът на свързване на middleware определя последователността на обработка — първият middleware получава оригиналните данни, последният ги предава на целевия процесор. Според данни на JetBrains (2026), тази архитектура позволява добавяне или изключване на middleware без промяна на съществуващия код, което улеснява тестването и A/B тестването на експериментални модули.
Middleware — общ модел, Interceptor — негов частен случай за HTTP. Middleware работи с всякакви потоци от данни: actions в Redux, събития в Bloc, HTTP заявки в Ktor. Interceptor винаги е обвързан с мрежовия слой и работи само с Request/Response. Разбирането на тази разлика помага при избора на правилната абстракция: за логване на действията на потребителя — middleware, за добавяне на хедъри — Interceptor. В големи проекти и двата модела често съществуват заедно: middleware управлява състоянието, Interceptor — HTTP комуникацията.
Redux middleware прихваща всеки dispatch action, преди да достигне до reducer. Това позволява логване на действия, изпълнение на асинхронни заявки чрез Redux Thunk или Redux Saga, промяна на action или условното му отменяне. Всеки middleware получава store (достъп до състоянието), next (препратка към следващия middleware или 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. Middleware прихваща всички NavigationAction, логва името на екрана в аналитичната система и извиква next(action) за продължаване на веригата. Ако next не беше извикана, action нямаше да достигне до reducer — по този начин може да се реализира условна навигация или блокиране на нежелани действия. Редът на middleware в масива определя последователността на обработка.
Redux Thunk — middleware, който позволява dispatch не само на action обекти, но и на функции. Функцията получава dispatch и getState, може да изпълнява async операции (API заявки чрез http клиент, четене от база данни) и да dispatche обикновени actions след завършване. Това е стандартният подход за работа с мрежови заявки в Redux приложения. Redux Saga използва генератори (yield) за по-сложни сценарии: отмяна на заявки, race conditions, паралелни операции и debounce на потребителски вход. Според данни на Redux Saga (2026), корутините на Saga се тестват и дебъгват по-лесно от вложените callback-и на Thunk.
Ktor Client от JetBrains изгражда HTTP обработка на базата на pipeline middleware. Всеки етап от заявката — установяване на връзка, изпращане на хедъри, четене на отговор — е представен от отделна фаза в pipeline. Разработчикът инсталира плъгини (middleware) чрез client.install { }, получавайки верига за обработка. Редът на инсталиране определя кой middleware обработва данните първи: 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 с инсталирани middleware плъгини. Logging — записва съдържанието на заявката и отговора. Auth — автоматично добавя Bearer токен с поддръжка за опресняване. ContentNegotiation — сериализира/десериализира JSON. HttpTimeout — задава времеви ограничения. Всеки плъгин е независим: в тестова среда Auth може да бъде изключен чрез промяна на конфигурацията на клиента, без да се променя кодът на заявките.
Dio — популярен HTTP клиент за Flutter, който използва Interceptor в ролята на middleware. Interceptor прихваща RequestOptions преди изпращане и Response след получаване, поддържайки верига от няколко прихващача. Dio Interceptor — аналог на OkHttp Interceptor за Dart/Flutter. Според данни на Dio (2026), RetryInterceptor и LogInterceptor са най-често използваните middleware в Flutter проекти.
Bloc няма вграден middleware като отделен компонент, но моделът се реализира чрез BlocObserver — глобален наблюдател, който получава събитията на всеки блок в приложението. BlocObserver.onEvent се извиква преди обработката на всяко събитие, onTransition — при всяка промяна на състоянието, onError — при всяко изключение. Това е пълноценен middleware за аналитика, логване, отчитане на грешки и наблюдение на производителността.
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 — middleware за Bloc на Dart. onEvent логва всяко събитие в Crashlytics, onTransition изпраща събития към аналитиката, onError записва изключения в отчитането на грешки. Свързването чрез BlocOverrides.runZoned прави наблюдателя глобален за всички блокове без промяна на техния код. За изключване в тестове е достатъчно да се предаде празен наблюдател или да не се презаписва BlocOverrides.
Middleware е ефективен за задачи, които засягат множество компоненти: логване, удостоверяване, аналитика, кеширане, наблюдение на производителността. Използвайте middleware, когато една и съща логика се повтаря в различни части на приложението — добавяне на токен към всяка заявка, логване на всяко действие на потребителя, аналитика на всяко преминаване между екрани. Според данни на Dio (2026), централизираната обработка чрез middleware намалява броя на грешките с 25% в сравнение с дублирането на код във всеки компонент поотделно.
Най-честата грешка — нарушаване на реда на middleware, когато първият прихващач очаква данни, които вторият добавя. Втората по честота — блокиращи операции в middleware на главната нишка: запис във файл, синхронни HTTP извиквания, криптиране. Третата — липса на обработка на изключения: ако middleware хвърли изключение, цялата верига се прекъсва и action не достига до reducer или заявката не се изпраща. Винаги обвивайте логиката на middleware в try-catch и логвайте грешките в Crashlytics или Sentry, без да прекъсвате веригата. Редовно проверявайте веригата на middleware при преглед на кода — това предотвратява деградацията на архитектурата.
Често задавани въпроси
Interceptor — частен случай на middleware за HTTP комуникация. Middleware — по-широк модел: може да обработва действия (Redux), събития (Bloc), HTTP (Ktor) и всякакви потоци от данни. Interceptor винаги е обвързан с мрежовия слой и работи само с Request/Response.
Използвайте фабричен метод или DI контейнер (Dagger, Koin, GetIt), който връща различен набор от middleware за dev и prod. В Redux подайте празен масив в тестовете. В Ktor — използвайте тестов HttpClient без плъгини. Основният принцип — middleware не трябва да бъде твърдо вграден в кода.
Да — middleware променя action преди предаването му към reducer или следващия middleware. Например, Redux middleware може да добави метаданни (userId, timestamp, deviceId) към всеки action без промяна на кода на dispatcher. Основно правило — не мутирайте оригиналния обект, а създавайте нов чрез spread оператора.
В Ktor термините са взаимозаменяеми — Ktor Client middleware и плъгин означават едно и също нещо. Всеки плъгин имплементира HttpClientPlugin и се инсталира чрез client.install { }. Всички плъгини се вграждат в pipeline на заявката, образувайки верига за обработка.
Чрез презаписване на BlocObserver.onError — глобален манипулатор, който се извиква при всяко изключение във всеки блок. Това е алтернатива на try-catch във всеки блок: един middleware централизирано обработва грешки, записва ги в Crashlytics и показва snackbar на потребителя.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също